关于.net:AS运算符在C#中的用处

The usefulness of AS operator in C#

本问题已经有最佳答案,请猛点这里访问。

Possible Duplicate:
Direct casting vs 'as' operator?

这个接线员在哪里有用?不是写这个:

1
2
3
Asset a = new Asset();
Stock s = a as Stock;       // s is null; no exception thrown
if (s != null) Console.WriteLine (s.SharesOwned);

你最好写些能扔出去的东西。我看到很多吨

(s != null)

在生产代码中,它真的变得很难看。例外情况在这种情况下更具描述性和自然性。甚至概念上:如果不是股票,你怎么可能没有资产?如果不是股票,则应为例外。


通常情况下,您不希望抛出异常,因为情况并不例外。你有一个frob物体,你知道它可以是Foo,也可以是Bar。因此,只有当它是一个Foo时,您才希望执行一些操作。

您试图在设计中避免这些情况,而使用虚拟方法。但有时候没有什么好办法。

所以与其绕道而行,

1
2
3
if (frob is Foo) {
    ((Foo) frob).Frobnicate();
}

你可以直接做到:

1
2
3
4
var asFoo = frob as Foo;
if (asFoo != null) {
    asFoo.Frobnicate();
}

如果没有其他方法,这至少更有效,因为您只需要测试一次类型相等(在as强制转换中)而不是两次(在is强制转换中)。

作为一个具体的例子,当您想要清除表单中的所有输入框时,这非常有用。您可以使用以下代码:

1
2
3
4
5
foreach (Control c in this.Controls) {
    var tb = c As TextBox;
    if (tb != null)
       tb.Clear();
}

在这里使用一个例外是没有意义的。


as执行is,如果is返回false分配null

听起来像一首歌,但它是答案,我经常使用它,就像在ASP.NET的findcontrol方法中一样:

1
Button myButton = e.item.FindControl("myControlId") as Button;

如果findcontrol发现与按钮不同的内容,则此类分配不会崩溃或引发。我非常喜欢这个……


You'd better write something that throws

不一定。用户不喜欢看到扔东西。您应该编写有效的代码。如果没有,你最好通过向用户道歉来妥善处理。as运算符在某些情况下很有用,例如,您将尝试强制转换,如果此强制转换不起作用,请为变量指定默认值,以便代码继续使用此默认值。这真的取决于上下文。


这取决于您的错误处理策略。我在代码库中工作,我们总是使用casting,而不是使用as操作符。但是,在某些情况下,as运算符非常有用,而且比异常更快。

例如,在下面的情况下,您喜欢什么?

1
2
3
4
5
6
7
8
9
10
11
12
13
public bool Process(int choice)
{
    try
    {
        Thing thing = GetRequiredThing(choice);
        SubThing subThing = (SubThing)thing;
    }
   catch (InvalidCastException ex)
   {
       // report ex.
       return false;
   }
}

1
2
3
4
5
6
7
8
9
10
public bool Process(int choice)
{
    Thing thing = GetRequiredThing(choice);
    SubThing subThing = thing as SubThing;
    if (subThing == null)
    {
        //report error;
        return false;
    }
}

如果不需要,则应始终使用as运算符。接你的电话。


异常不是为流控制而设计的,根据定义,它们是正常事件序列的异常。如果转换失败是可以接受的,则使用as。相反,如果不能将"A"转换为股票永远不会发生,您可以使用简单的s=(Stock)a;,这将抛出它自己的异常。不过,此时您无法控制异常。

以下内容使开发人员能够更清晰地处理异常情况:

1
2
3
4
5
6
7
8
9
Asset a= new Asset();
Stock s= a as Stock();
if(s == null) {
    // Safely exit from call if possible, maybe make calls to logging mechanism or
    // other ways of determining why an exception occurred.  Also, could throw custom
    // Exception if needed with much more detailed info.
} else {
    // Continue normal flow
}

你可以这样做:

1
2
3
4
5
6
7
8
9
10
11
12
Asset a= new Asset();
try
{
    Stock s= (Stock);
    // Continue normal flow
}
catch (InvalidCastException exc)
{
    // Safely exit from call if possible, maybe make calls to logging mechanism or
    // other ways of determining why an exception occurred.  Also, could throw custom
    // Exception if needed with much more detailed info.
}

但是,这将异常用作流控制,而且代价高昂,设计也不好。


你有什么要求?

如果资产是股票,请打印所拥有的股票数量。

在这种情况下,as操作符非常有用,但您必须检查stock != null。这是要求所暗示的。

打印股票拥有的股票数量。如果提供了其他资产,则是一个错误。

然后应该编写引发异常的代码。


是的,as运算符是有用的,是的,它可能被误用。

如果您确定某个变量xT类型,则应使用常规强制转换。

1
T y = (T)x;

如果T1T2都是变量x的有效类型,则可以使用as检查类型并执行一次强制转换操作。


如果Asset是从Stock继承来的,那就可以了。这是我见过的唯一一种情况,尽管您可以在接口的情况下使用它。