直接铸造与“ as”运算符?
考虑以下代码:
void Handler(object o, EventArgs e)
{// I swear o is a stringstring s = (string)o; // 1//-OR-string s = o as string; // 2// -OR-string s = o.ToString(); // 3
}
三种类型的转换之间有什么区别(好吧,第三个类型不是转换,但是您有意图)。 应该首选哪一个?
#1楼
当试图获取任何可能为空的任何类型的字符串表示形式时,我喜欢下面的代码行。 它紧凑,可以调用ToString(),并且可以正确处理null。 如果o为null,则s将包含String.Empty。
String s = String.Concat(o);
#2楼
“ as”基于“ is”,这是一个关键字,它在运行时检查对象是否在政治上兼容(基本上可以进行强制转换),如果检查失败,则返回null。
这两个是等效的:
使用'as':
string s = o as string;
使用“是”:
if(o is string) s = o;
elses = null;
相反,c样式强制转换也是在运行时进行的,但是如果无法进行强制转换,则会引发异常。
仅添加一个重要事实:
“ as”关键字仅适用于引用类型。 您不能:
// I swear i is an int
int number = i as int;
在这种情况下,您必须使用投射。
#3楼
string s = (string)o; // 1
如果o
不是string
则抛出InvalidCastException 。 否则,将o
分配给s
,即使o
为null
。
string s = o as string; // 2
分配null
到s
,如果o
是不是一个string
,或者o
为null
。 因此,您不能将其与值类型一起使用(在这种情况下,运算符永远不会返回null
)。 否则,将o
分配给s
。
string s = o.ToString(); // 3
如果o
为null
则导致NullReferenceException 。 将o.ToString()
返回的值o.ToString()
s
,无论o
是什么类型。
大多数转换使用1-简单明了。 我倾向于几乎从不使用2,因为如果某些类型不正确,我通常希望发生异常。 我只看到这种返回null类型的功能需要使用错误代码(例如,返回null =错误,而不是使用异常)的错误设计的库。
3不是强制转换,而只是方法调用。 在需要非字符串对象的字符串表示形式时使用它。
#4楼
这实际上取决于您是否知道o
是否为字符串以及您要如何处理。 如果您的评论表示o
确实是一个字符串,则我希望使用直接(string)o
强制转换-不太可能失败。
使用直接强制转换的最大优点是,当它失败时,您会收到InvalidCastException ,它告诉您几乎所有出了什么问题。
使用as
运算符,如果o
不是字符串,则将s
设置为null
,如果不确定并想要测试s
,则非常方便:
string s = o as string;
if ( s == null )
{// well that's not good!gotoPlanB();
}
但是,如果不执行该测试,则稍后将使用s
并引发NullReferenceException 。 这些往往是更常见, 很多难以追查,一旦他们在野外发生了,因为几乎每行取消引用变量,可能会抛出一个。 在另一方面,如果你想投的值类型(任何原始的,或结构如日期时间 ),你必须使用直投-将as
将无法正常工作。
在转换为字符串的特殊情况下,每个对象都有一个ToString
,因此,如果o
不为null,并且您认为ToString
方法可以完成您想做的事情,那么您的第三个方法就可以了。
#5楼
“(string)o”将导致InvalidCastException,因为没有直接强制转换。
“ o as string”将导致s为空引用,而不是引发异常。
“ o.ToString()”本身不是任何形式的转换,它是由对象实现的方法,因此由.net中的每个类以某种方式对.NET的实例“做某事”实现调用它的类并返回一个字符串。
不要忘记,要转换为字符串,还有Convert.ToString(someType instanceOfThatType),其中someType是一组类型之一,本质上是框架的基本类型。
#6楼
string s = (string)o;
绝对应该是另一回事时使用。string s = o as string;
当某事可能是另一回事时使用。string s = o.ToString();
当您不在乎它是什么但只想使用可用的字符串表示形式时使用。
#7楼
2对于强制转换为派生类型很有用。
假设a是动物:
b = a as Badger;
c = a as Cow;if (b != null)b.EatSnails();
else if (c != null)c.EatGrass();
用最少的铸件会得到反馈。
#8楼
如果您已经知道它可以转换为哪种类型,请使用C样式的转换:
var o = (string) iKnowThisIsAString;
请注意,只有使用C样式强制转换,您才能执行显式类型强制。
如果您不知道它是否是所需的类型,并且打算使用它,请使用as关键字:
var s = o as string;
if (s != null) return s.Replace("_","-");//or for early return:
if (s==null) return;
注意, as不会调用任何类型转换运算符。 仅当对象不为null且本机为指定类型时,它才会为非null。
使用ToString()获取任何对象的人类可读的字符串表示形式,即使它不能转换为字符串也是如此。
#9楼
string s = o as string; // 2
首选,因为它避免了双重铸造的性能损失。
#10楼
当您使用FindControl方法时,as关键字在asp.net中很好。
Hyperlink link = this.FindControl("linkid") as Hyperlink;
if (link != null)
{...
}
这意味着您可以对类型化的变量进行操作,而不必像直接强制转换那样从object
强制转换它:
object linkObj = this.FindControl("linkid");
if (link != null)
{Hyperlink link = (Hyperlink)linkObj;
}
这不是一件大事,但它节省了代码行和变量赋值,而且可读性强
#11楼
如果我可能要添加一些内容,那么所有给出的答案都是好的:要直接使用字符串的方法和属性(例如ToLower),您不能编写:
(string)o.ToLower(); // won't compile
您只能写:
((string)o).ToLower();
但您可以改为:
(o as string).ToLower();
as
选项更具可读性(至少在我看来)。
#12楼
由于没有人提到它,因此关键字最接近Java的instanceOf是:
obj.GetType().IsInstanceOfType(otherObj)
#13楼
根据在此页面上运行的实验: http : //www.dotnetguru2.org/sebastienros/index.php/2006/02/24/cast_vs_as
(此页面有时会显示一些“非法引荐来源网址”错误,因此请刷新一下)
结论是,“ as”运算符通常比强制转换更快。 有时快很多倍,有时快一点。
我个人认为“ as”也更易读。
因此,由于它既更快又更“安全”(不会抛出异常),并且可能更易于阅读,所以我建议始终使用“ as”。
#14楼
看来他们两个在概念上是不同的。
直接铸造
类型不必严格相关。 它有各种口味。
- 自定义隐式/显式强制转换:通常创建一个新对象。
- 值类型隐式:复制而不会丢失信息。
- 值类型显式:复制和信息可能会丢失。
- IS-A关系:更改引用类型,否则引发异常。
- 相同类型: “铸造是多余的”。
感觉该对象将被转换成其他东西。
AS运营商
类型有直接关系。 如:
- 引用类型: IS-A关系对象总是相同的,只是引用发生了变化。
- 值类型: 复制拳击和可为空的类型。
感觉就像您将以不同的方式处理对象。
样品和IL
class TypeA{public int value;}class TypeB{public int number;public static explicit operator TypeB(TypeA v){return new TypeB() { number = v.value };}}class TypeC : TypeB { }interface IFoo { }class TypeD : TypeA, IFoo { }void Run(){TypeA customTypeA = new TypeD() { value = 10 };long longValue = long.MaxValue;int intValue = int.MaxValue;// Casting TypeB typeB = (TypeB)customTypeA; // custom explicit casting -- IL: call class ConsoleApp1.Program/TypeB ConsoleApp1.Program/TypeB::op_Explicit(class ConsoleApp1.Program/TypeA)IFoo foo = (IFoo)customTypeA; // is-a reference -- IL: castclass ConsoleApp1.Program/IFooint loseValue = (int)longValue; // explicit -- IL: conv.i4long dontLose = intValue; // implict -- IL: conv.i8// AS int? wraps = intValue as int?; // nullable wrapper -- IL: call instance void valuetype [System.Runtime]System.Nullable`1<int32>::.ctor(!0)object o1 = intValue as object; // box -- IL: box [System.Runtime]System.Int32TypeD d1 = customTypeA as TypeD; // reference conversion -- IL: isinst ConsoleApp1.Program/TypeDIFoo f1 = customTypeA as IFoo; // reference conversion -- IL: isinst ConsoleApp1.Program/IFoo//TypeC d = customTypeA as TypeC; // wouldn't compile}
#15楼
使用直接转换string s = (string) o;
如果在您的应用的逻辑上下文中, string
是唯一有效的类型。 使用这种方法,您将获得InvalidCastException
并实现Fail-fast的原理。 你的逻辑将受到保护,免受进一步传递了无效的类型,或者使用得到的NullReferenceException as
运营商。
如果逻辑期望几种不同类型,则将string s = o as string;
并检查是否为null
或use is
运算符。
C#7.0中出现了新的很酷的功能,以简化转换,并且检查是否为模式匹配 :
if(o is string s)
{// Use string variable s
}orswitch (o)
{case int i:// Use int variable ibreak;case string s:// Use string variable sbreak;}
#16楼
C#支持以下两种类型的类型转换(广播)形式:
|
(简历
•在给定表达式中将v的静态类型转换为c
•仅当v的动态类型为c或c的子类型时才可能
•如果不是,则抛出InvalidCastException
|
v作为C
•(c)v的非致命变体
•因此,在给定表达式中将v的静态类型转换为c
•如果v的动态类型不是c或c的子类型,则返回null
#17楼
我想引起注意as运算符的以下细节:
https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/keywords/as
请注意,as运算符仅执行参考转换,可为空的转换和装箱转换。 as运算符不能执行其他转换,例如用户定义的转换,而应使用强制转换表达式来执行。
直接铸造与“ as”运算符?相关推荐
- kotlin方法类型_Kotlin类型检查,Kotlin类型铸造
kotlin方法类型 Today we will look into Kotlin type checking and smart type casting. We will use Kotlin O ...
- python 位运算与等号_Python 运算符
和大多数语言一样,Python也有很多运算符,并且运算符跟其他语言的运算符大同小异接下来一一介绍: 算术运算符: 运算符描述实例 +加 - 两个对象相加a+b的输出结果是30 -减 - 得到复数或者一 ...
- 第一个python程序:定义,列表,元组,集合,求并集交集,键和值,运算符,缩进
''' 来源:天善智能韦玮老师课堂笔记 ''' print("定义") a = 6 # python里无需定义 print("a=",a) a += 1 # + ...
- C++ 重载运算符 operator
operator 是什么 operator 是C++的一个关键字,它和运算符(+,-,*,/,=,等等)一起使用,表示一个运算符重载函数 operator 没有返回语句 operator 的作用 : ...
- Python 位运算符
Python 位运算符有 1 按位与(&) 2 按位或(|) 3 按位异或(^) 4 按位取反(~) 5 左位移(<<) 6 右位移(>>) 运算符 描述 & ...
- C++ sizeof 运算符的使用
sizeof 是C++ 中 唯一的一个带字母的运算符, sizeof 的功能: 返回指定的数据类型或者表达式值的数据类型在内存中所占的字节数. sizeof 运算符的使用 1 sizeof(类型) ...
- C++ 获取内存地址(取值运算符)
c++ 获取内存地址使用取值运算符 : & 下面看下& 的使用 #include <iostream> using namespace std; int main() {s ...
- Python 算术运算符
算数运算符: 运算符 说明 实例 + 加 1+2 结果为3 - 减 2-1 结果为1 * 乘 2 * 2 结果为4 / 除 7/2 结果为3.5 % 取模 返回除法的余数 7%2 结果为1 // ...
- Python 运算符之成员运算符 in 与 not in
Python成员运算符 in 是判断值在某个列表中就返回True , Python成员运算符 not in 是判断值不在某个列表中就返回True , 下面是简单的一个list 帮助理解 list_ ...
最新文章
- mockito mock void方法_纯干货,浅谈Mockito在单元测试中的实际应用
- 比较两个引用的几种方法
- 从0到掌握Java泛型有这一篇博客就够了
- HDFS、MR、Kafka、Storm、Spark、Hbase、Redis原理图
- python入门--基本语法
- 前端学习(1682):前端系列实战课程之让蛇改变方向
- 复数幂用java程序怎么求_蓝桥杯——复数幂 (2018JavaAB组第3题)
- SpringBoot 2 快速整合 | 统一异常处理
- ram自己写?用IP?
- DOM—外部插入.after()、.before()、.insertAfter()和.insertBefore()与内部插入.prepend()和.prependTo()...
- 小猫爪:动手笔记01-FreeRTOS移植
- 量化投资之股票统计套利:基于BP神经网络
- python 绘制qq图
- windows下查看硬盘序列号、设备序列号、操作系统版本和安装时间、系统启用时间等命令
- 自编码器(autoencoder)了解一下
- 视频教程-Web前端开发利器 SPRY框架之表单验证-JavaScript
- swap()函数实现变量值的交换
- 我的世界服务器显示你没有权限,你没有权限与....交互 - 有问必答 - 最MC论坛 - 我的世界_Minecraft_联机_服主_资讯_MOD_皮肤_交流_作品_中文论坛...
- 告诉你究竟DevOps是什么?
- centos7重新安装polket
热门文章
- Android studio 4.1 不显示光标当前的类名、方法名
- SDK location not found. Define location with sdk.dir in the local.properties file or with an ANDROID
- Android Launcher3(一) -- 启动过程
- 【剑指offer-Java版】35第一个只出现一次的字符
- python cgi nginx_nginx uwsgi和cgi python脚本
- C语言函数集(二十一)
- 电销机器人价格_电销机器人哪个牌子最好(强烈推荐)
- 一个页面区分管理者和普通用户如何设计_产品经理要做的操作权限/数据权限设计...
- 数据挖掘-数据清理过程
- Python应用——自定义函数:分割PDF文件函数