C#中”as”关键字的意义是什么?

What's the point of “As” keyword in C#

来自文档:

The as operator is like a cast except that it yields null on conversion failure instead of raising an exception. More formally, an expression of the form:

1
   expression as type

is equivalent to:

1
  expression is type ? (type)expression : (type) null

except that expression is evaluated only once.

所以你为什么不选择这样或那样做呢?为什么有两个铸造系统?


他们不是两个铸造系统。这两个词的作用相似,但含义却截然不同。"as"的意思是"我认为这个对象实际上可能是另一种类型;如果不是,请给我空值。"强制转换表示两种情况之一:

  • 我确信这个物体实际上是另一种类型。这样做吧,如果我错了,就让程序崩溃。

  • 我确信这个对象不是其他类型的,但是有一种众所周知的方法可以将当前类型的值转换为所需类型。(例如,将int转换为short。)这样做,如果转换实际上不起作用,程序就会崩溃。

有关更多详细信息,请参阅我关于这个主题的文章。

http://blogs.msdn.com/b/ericlippet/archive/2009/10/08/what-s-the-difference-between-as-and-cast-operators.aspx


效率和性能

执行强制转换的一部分是一些集成的类型检查;因此用显式类型检查预先固定实际强制转换是多余的(类型检查会发生两次)。使用As关键字确保只执行一个类型检查。您可能会认为"但是它必须执行空检查而不是第二个类型检查",但是与类型检查相比,空检查非常有效,而且性能也非常好。

1
2
3
4
5
if (x is SomeType )
{
  SomeType y = (SomeType )x;
  // Do something
}

进行2次检查,而

1
2
3
4
5
SomeType y = x as SomeType;
if (y != null)
{
  // Do something
}

使1X——与类型检查相比,空检查非常便宜。


因为有时候,如果你不能像你期望的那样投射,你希望事情失败;有时候,你不在乎,如果一个给定的物体不能投射,你只想丢弃它。

它基本上是用try块包装的常规强制转换的更快版本;但是As的可读性更高,而且还节省了输入。


它允许快速检查,而无需尝试/强制转换开销,在某些情况下,处理基于消息的继承树可能需要这种开销。

我经常使用它(输入消息,对特定的子类型作出反应)。Try/Cast速度会明显慢一些(许多尝试/捕获每一条消息的帧),我们在这里讨论每秒处理200000条消息。


让我给你一个真实的场景,你将在哪里使用这两个。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Foo
{
  private int m_Member;

  public override bool Equals(object obj)
  {
    // We use 'as' because we are not certain of the type.
    var that = obj as Foo;
    if (that != null)
    {
      return this.m_Member == that.m_Member;
    }
    return false;  
  }
}

还有…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Program
{
  public static void Main()
  {
    var form = new Form();
    form.Load += Form_Load;
    Application.Run(form);
  }

  private static void Form_Load(object sender, EventArgs args)
  {
    // We use an explicit cast here because we are certain of the type
    // and we want an exception to be thrown if someone attempts to use
    // this method in context where sender is not a Form.
    var form = (Form)sender;

  }
}

我通常根据代码的语义选择其中一个。

例如,如果您有一个object,您知道它必须是string,那么使用(string),因为这表示编写代码的人确信对象是string,如果不是这样,那么我们已经有比将要抛出的运行时强制转换异常更大的问题。

如果您不确定对象是特定类型,但希望在对象是特定类型时具有逻辑性,请使用As。您可以使用is操作符,然后使用cast,但As操作符更有效。


也许例子会有帮助:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// Regular casting
Class1 x = new Class1();
Class2 y = (Class2)x; // Throws exception if x doesn't implement or derive from Class2

// Casting with as
Class2 y = x as Class2; // Sets y to null if it can't be casted.  Does not work with int to short, for example.

if (y != null)
{
  // We can use y
}

// Casting but checking before.
// Only works when boxing/unboxing or casting to base classes/interfaces
if (x is Class2)
{
  y = (Class2)x; // Won't fail since we already checked it
  // Use y
}

// Casting with try/catch
// Works with int to short, for example.  Same as"as"
try
{
  y = (Class2)x;
  // Use y
}
catch (InvalidCastException ex)
{
  // Failed cast
}