什么时候应该在C#中使用as关键字
当你想在大多数时候想要改变类型时,你只想使用传统的演员表。
var value = (string)dictionary[key];
这很好,因为:
- 它很快
- 如果出现问题,它会抱怨(而不是给对象是空的例外)
那么什么是使用的好例子, as
我无法真正找到或想到完全适合它的东西?
注意:实际上我认为有时候编译器会阻止使用演员as
作品(generics相关?)。
使用时对象对象不是您想要的类型,并且如果是,则要采取不同的行为。 例如,在某些伪代码中:
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(this IEnumerable source) { IList list = source as IList; if (list != null) { return list.Count; } IList genericList = source as IList ; 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
是一个+是演员。 根据上面的例子,它几乎总是在之后使用无效检查。
每次当您需要安全施放对象时无例外地使用:
MyType a = (MyType)myObj; // throws an exception if type wrong MyType a = myObj as MyType; // return null if type wrong
用于避免双重投射逻辑,如:
if (x is MyClass) { MyClass y = (MyClass)x; }
运用
MyClass y = x as MyClass; if (y == null) { }
为案例#1生成的FYI,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
不会抛出强制转换exception,但只要在强制转换失败时返回null
。
Enumerable中.Count()的实现使用它来使Count()更快地进行收集
实现如下:
ICollection collection = source as ICollection ; if (collection != null) { return collection.Count; } ICollection collection2 = source as ICollection; if (collection2 != null) { return collection2.Count; }
尝试将源转换为ICollection或ICollection都具有Count属性。 如果失败,Count()将遍历整个源。 因此,如果您不确定类型并且之后需要该类型的对象(如上例所示),则应使用as
。
如果您只想测试对象是否属于给定类型,则使用is
并且如果您确定该对象属于给定类型(或派生自/实现该类型),那么您可以
Ok Nice回复所有人,但让我们有点实用。 在您自己的代码中,即非供应商代码,AS关键字的REALfunction不会脱颖而出。
但是当在WPF / silverlight中处理供应商对象时,AS关键字是一个真正的奖励。 例如,如果我在Canvas上有一系列控件并且我想跟踪thelast selectedControl,但是当我单击Canvas时清除跟踪变量我会这样做:
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 keyoword的另一个原因是当您的Class实现了一个或多个Interfaces并且您希望显式只使用一个接口时:
IMySecond obj = new MyClass as IMySecond
虽然这里没有必要,但如果MyClass没有实现IMySecond,它将为变量obj赋值null
以下是来自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”关键字,在非特殊情况下,您希望转换失败。 如果你指望一个强制转换成功并且没有准备接收任何失败的对象,你应该使用()强制转换运算符,以便抛出适当且有用的exception。