我最近了解了一种不同的演员方式。而不是使用
SomeClass someObject = (SomeClass) obj;
可以使用以下语法:
SomeClass someObject = obj as SomeClass;
如果obj不是SomeClass,它似乎返回null,而不是抛出一个类转换异常。
我发现如果转换失败并且我尝试访问someObject变量,这会导致NullReferenceException。所以我想知道这种方法背后的理由是什么?为什么要使用这种方式而不是(旧)方式 - 它似乎只是将失败的演员问题“更深”地转移到代码中。
答案 0 :(得分:147)
使用“经典”方法,如果转换失败,则抛出异常。使用as方法,它会导致null,可以检查它,并避免抛出异常。
此外,您只能对引用类型使用“as”,因此如果要对值类型进行类型转换,则仍必须使用“经典”方法。
注意:强>
as
方法只能用于可以分配null
值的类型。这种用法仅表示引用类型,但是当.NET 2.0出现时,它引入了可空值类型的概念。由于可以为这些类型分配null
值,因此它们可以与as
运算符一起使用。
答案 1 :(得分:29)
空比较 MUCH 比抛出和捕获异常更快。例外有很大的开销 - 堆栈跟踪必须组装等。
异常应该表示意外状态,这通常不代表情况(as
更好地工作时)。
答案 2 :(得分:25)
在某些情况下,处理null
比处理异常更容易。特别是,合并算子很方便:
SomeClass someObject = (obj as SomeClass) ?? new SomeClass();
它还简化了您所在的代码(不使用多态性,并根据对象的类型进行分支):
ClassA a;
ClassB b;
if ((a = obj as ClassA) != null)
{
// use a
}
else if ((b = obj as ClassB) != null)
{
// use b
}
根据MSDN page的规定,as
运算符相当于:
expression is type ? (type)expression : (type)null
避免了完全支持更快类型测试的异常,但也限制了它对支持null
(引用类型和Nullable<T>
)的类型的使用。
答案 3 :(得分:7)
as
运算符在某些情况下很有用。
null
第三点是微妙但重要的。在使用强制转换运算符的转换和使用as
运算符成功的转换之间没有1-1映射。 as
运算符严格限于CLR转换,不会考虑用户定义的转换(转换运算符)。
具体而言,as
运算符仅允许以下内容(来自C#lang规范的第7.9.11节)
答案 4 :(得分:3)
当您真正不知道变量可能是什么类型时,as
关键字非常有用。如果您有一个函数将遵循不同的代码路径,具体取决于参数的实际类型,那么您有两个选择:
首先,使用普通演员:
if(myObj is string)
{
string value = (string)myObj;
... do something
}
else if(myObj is MyClass)
{
MyClass = (MyClass)myObj;
}
这要求您使用is
检查对象的类型,这样您就不会尝试将其转换为失败的对象。这也有点多余,因为is
- 类型检查在强制转换中再次完成(因此如果需要,它可以抛出异常)。
另一种方法是使用as
。
string myString = myObj as string;
MyClass myClass = myObj as MyClass;
if(myString != null)
{
}
else if(myClass != null)
{
}
这使得代码更短,并且还消除了冗余类型检查。
答案 5 :(得分:1)
如果不是有效的强制转换,则使用as将返回null,除了在try / catch中包装强制转换之外,还允许您执行其他操作。我讨厌经典演员。如果我不确定,我总是使用演员。另外,例外是昂贵的。空检查不是。
答案 6 :(得分:1)
我认为最好的“规则”只是在预期您的主题不是您要投放的对象时才使用'as'关键字:
var x = GiveMeSomething();
var subject = x as String;
if(subject != null)
{
// do what you want with a string
}
else
{
// do what you want with NOT a string
}
然而,当你的主题应该是你所投射的类型时,请使用'经典演员',就像你所说的那样。因为如果它不是你期望的类型,你将得到一个适合特殊情况的例外。
答案 7 :(得分:0)
这里没有什么深刻的发生。基本上,测试某些东西以确定它是否属于某种类型(即使用'as')是很方便的。您可能需要检查“as”调用的结果,以查看结果是否为空。
当您期望某个强制转换工作并且您希望抛出异常时,请使用“经典”方法。
答案 8 :(得分:0)
您使用“as”语句来避免出现异常的可能性,例如:你可以通过逻辑优雅地处理演员失败。只有在确定对象属于所需类型时才使用强制转换。我几乎总是使用“as”然后检查null。
答案 9 :(得分:0)
我认为如果将转换的结果传递给您知道将在不抛出ArgumentNullException
之类的情况下处理空引用的方法,它会很有用。
我倾向于发现as
的用处很少,因为:
obj as T
慢于:
if (obj is T)
...(T)obj...
使用as
对我来说是一个非常边缘的场景,所以我想不出任何关于何时使用它而不仅仅是投射和处理(更具信息性)的投射异常的一般规则进一步上升。