当你想改变类型时,大多数时候你只想使用传统的演员阵容。
var value = (string)dictionary[key];
这很好,因为:
那么使用
as
的一个很好的例子是什么?我真的找不到或想不出完全适合它的东西?
注意:实际上,我认为有时编译器会阻止使用
as
起作用的强制转换(与泛型相关?)。
当对象不属于您想要的类型并且您想要以不同的方式操作时,请使用
as
有效。例如,在伪代码中:
foreach (Control control in foo)
{
// Do something with every control...
ContainerControl container = control as ContainerControl;
if (container != null)
{
ApplyToChildren(container);
}
}
或者 LINQ to Objects 中的优化(很多这样的例子):
public static int Count<T>(this IEnumerable<T> source)
{
IList list = source as IList;
if (list != null)
{
return list.Count;
}
IList<T> genericList = source as IList<T>;
if (genericList != null)
{
return genericList.Count;
}
// Okay, we'll do things the slow way...
int result = 0;
using (var iterator = source.GetEnumerator())
{
while (iterator.MoveNext())
{
result++;
}
}
return result;
}
所以使用
as
就像 is
+ 演员表。根据上面的示例,它几乎总是随后与无效检查一起使用。
as
:
MyType a = (MyType)myObj; // throws an exception if type wrong
MyType a = myObj as MyType; // return null if type wrong
As 用于避免双重转换逻辑,如下所示:
if (x is MyClass)
{
MyClass y = (MyClass)x;
}
使用
MyClass y = x as MyClass;
if (y == null)
{
}
仅供参考,为案例 #1 生成的 IL:
// if (x is MyClass)
IL_0008: isinst MyClass
IL_000d: ldnull
IL_000e: cgt.un
IL_0010: ldc.i4.0
IL_0011: ceq
IL_0013: stloc.2
IL_0014: ldloc.2
IL_0015: brtrue.s IL_0020
IL_0017: nop
// MyClass y = (MyClass)x;
IL_0018: ldloc.0
IL_0019: castclass MyClass
IL_001e: stloc.1
对于案例#2:
// MyClass y = x as MyClass;
IL_0008: isinst MyClass
IL_000d: stloc.1
// if (y == null)
IL_000e: ldloc.1
IL_000f: ldnull
IL_0010: ceq
IL_0012: stloc.2
IL_0013: ldloc.2
IL_0014: brtrue.s IL_0018
使用
as
不会抛出强制转换异常,而只是在强制转换失败时返回 null
。
Enumerable 中 .Count() 的实现使用它来使 Count() 进行收集更快
实现方式如下:
ICollection<TSource> collection = source as ICollection<TSource>;
if (collection != null)
{
return collection.Count;
}
ICollection collection2 = source as ICollection;
if (collection2 != null)
{
return collection2.Count;
}
尝试将源转换为 ICollection 或 ICollection 都具有 Count 属性。 如果失败,Count() 将迭代整个源。 因此,如果您不确定类型并且之后需要该类型的对象(如上面的示例),您应该使用
as
。
如果您只想测试对象是否属于给定类型,请使用
is
并且如果您确定该对象属于给定类型(或派生自/实现该类型),那么您可以强制转换
好吧,大家的回复都很好,但让我们来点实际的吧。在您自己的代码(即非供应商代码)中,AS 关键字的真正威力不会凸显出来。
但是,当处理 WPF/silverlight 中的供应商对象时,AS 关键字是一个真正的好处。 例如,如果我在画布上有一系列控件,并且我想跟踪最后一个选定的控件,但当我单击画布时清除跟踪变量,我会这样做:
private void layoutroot_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
//clear the auto selected control
if (this.SelectedControl != null
&& sender is Canvas && e.OriginalSource is Canvas)
{
if ((sender as Canvas).Equals(( e.OriginalSource as Canvas)))
{
this.SelectedControl = null;
}
}
}
使用 AS 关键字的另一个原因是当您的类实现 1 个或多个接口并且您只想显式地仅使用一个接口时:
IMySecond obj = new MyClass as IMySecond
虽然这里没有必要,但如果 MyClass 没有实现 IMySecond ,它会将 null 赋给变量 obj
这是来自 http://blog.nerdbank.net/2008/06/when-not-to-use-c-keyword.html
的片段class SomeType {
int someField;
// The numeric suffixes on these methods are only added for reference later
public override bool Equals1(object obj) {
SomeType other = obj as SomeType;
if (other == null) return false;
return someField == other.SomeField;
}
public override bool Equals2(object obj) {
if (obj == null) return false;
// protect against an InvalidCastException
if (!(obj is SomeType)) return false;
SomeType other = (SomeType)obj;
return someField == other.SomeField;
}
}
上面的 Equals1 方法比 Equals2 更高效(并且更容易阅读),尽管它们完成了相同的工作。 Equals1 编译为执行一次类型检查和强制转换的 IL,而 Equals2 编译为首先对“is”运算符执行类型比较,然后作为 () 运算符的一部分一起执行类型比较和强制转换。所以在这种情况下使用“as”实际上更有效。事实上,它更容易阅读是一个好处。
总之,仅当您期望强制转换在非例外情况下失败时才使用 C#“as”关键字。如果您指望强制转换会成功,但不准备接收任何失败的对象,则应使用 () 强制转换运算符,以便抛出适当且有用的异常。
只是想补充一点,使用
as
后跟 null
检查可以再简化一步:
而不是
MyClass y = x as MyClass;
if (y == null)
{
}
可以直接做
if (x is Myclass y){
//y is now "MyClass", if x was a different class, we are not even here.
}
可以轻松地链接东西:
if (x is Double d){
//Work with Double d
}else if (x is Int32 i){
//Work with Int i
}