在C#中使用“as”是一种安全的铸造方式吗?

时间:2011-06-17 16:11:32

标签: c# casting

我想知道在下面的代码中使用关键字“as”是否是一种安全的方式(即不会爆炸)在C#中进行投射:

public void abc(ref Object dataSource)
{
    DataTable table = dataSource as DataTable;
}

有更安全的投射方式吗?

11 个答案:

答案 0 :(得分:40)

它不会爆炸......但这并不一定意味着它是安全的。

通常当我使用强制转换进行引用转换时,这是因为我确实认为执行时类型是我指定的类型。如果不是,则表示我的代码中存在错误 - 我宁愿将其表现为异常。

如果您的系统中存在错误数据,那么继续好像一切正​​常就是危险路径,而不是安全路径。这就是as将你带走的方式,而演员会抛出一个InvalidCastException,在你有机会对坏数据造成混乱之前中止你所做的一切。

如果对象不是给定类型的有效,则

as是好的 - 如果它不表示错误。您几乎总是看到以下模式:

Foo x = y as Foo;
if (x != null)
{
    ...
}

有关as的详细信息,请参阅MSDN

另请注意,可能不希望在您的方法中使用ref。有关详细信息,请参阅我的article on parameter passing。大多数时候,如果我看到人们经常使用ref,那是因为他们不明白它的真正含义:)

答案 1 :(得分:12)

这取决于你所说的“安全”。问问自己哪个更安全:带断路器的设备,还是没有断路器的设备?没有保险丝的人更有可能洗完衣服,但也更容易烧毁你的房子。

您可能知道,在C#中进行显式转换有两种主要方法:

foo = (MyType)myObject;    //Cast myObject to MyType or throw an error
foo = myObject as MyType;  //Cast myObject to MyType or set foo to null

不同之处在于,如果运行时不知道如何将myObject强制转换为MyType,则第一行将抛出异常,而第二行仅将foo设置为{ {1}}。如果生成在null中的对象不是myObject,或者MyType没有明确转换为MyType,则会发生这种情况。

哪一个更安全?好吧,如果“安全”意味着“如果演员表无效则不会抛出异常”,那么myObject表单会更安全。如果投射失败,as会立即爆炸,但如果您尝试对(MyType)myObject执行某些操作myObject as MyType,则foo只会爆炸({1}}例如调用null)。

另一方面,有时会抛出异常是最安全的事情。如果您的代码中有错误,您可能想立即知道。如果始终期望foo.ToString()myObject,那么失败的演员表示某处存在错误。如果你继续进行铸造工作,那么你的程序会突然处理垃圾数据!它可能会进一步爆炸,使调试变得困难,或者 - 更糟糕 - 它可能永远不会爆炸,只是静静地做你没想到的事情。这可能会造成各种各样的破坏。

因此,这两种形式都不是本质上安全或正确的,它们只适用于不同的事物。如果出现以下情况,您可以使用MyType表单:

  1. 您不确定myObject as MyType是什么类型
  2. 您希望对myObject执行某些操作,但前提是myObject类型
  3. MyType可能不是myObject,而且并不意味着存在错误
  4. 一个例子是当你有一组不同的WebForm控件时,你想要清除它们中的所有TextBox:

    MyType

    通过这种方式,您的TextBox会被清除,其他所有内容都会被遗漏。

答案 2 :(得分:5)

DataTable table = dataSource as DataTable;

如果演员表不成功,使用as将返回null,因此不会爆炸。 - 这意味着您必须处理代码其余部分中tablenull的情况。

答案 3 :(得分:4)

as不会爆炸,但如果转换失败,变量将设置为null。你需要检查那个案例。

DataTable table = dataSource as DataTable;
if (table == null)
{
    // handle case here.
}

答案 4 :(得分:2)

如果演员表无效,'as'运算符不会抛出异常。它只返回null。 ()方法将抛出异常。所以回答你的问题,这是最安全的方式。

这基本上是你需要的方式:

if( x is MyType )
{
   MyType y = (MyType) x;
}

MyType y = x as MyType;
if( y != null )
{
   // Do stuff
}

答案 5 :(得分:2)

这是一种安全的方式来投射它不会导致异常的事实。但是,如果您不小心,它可能会导致隐藏的错误。

使用as时,如果强制转换失败,则生成的变量为null。如果你没有检查这个,那么当你试图访问变量时你将会得到一个NullReferenceException,并且它不清楚它为什么会失败(例如它是null,因为转换失败或者做了别的事后来导致它为空)

答案 6 :(得分:2)

如果这是“安全”的意思,它不会抛出异常。但是,如果强制转换失败,table将为空。

DataTable table = dataSource as DataTable;

如果转换失败,则不会抛出异常。将改为null。

DataTable table = (DataTable)dataSource;

如果演员表失败,将抛出异常。

在这方面是安全的,但是如果转换可能失败,那么添加一个空检查来处理它。

答案 7 :(得分:1)

取决于您要做的事情:

DataTable table = dataSource as DataTable;
if (table != null) ...

表示“dataSource 可能DataTable,我将检查它不是null。”

DataTable table = (DataTable) dataSource;

表示“dataSource 肯定是DataTable,如果不是”{<1>}则会出现严重错误。

答案 8 :(得分:0)

如果dataSource可以作为DataTable转换,它将完成工作,这是安全的。但如果您担心它没有成功投射,您可以先检查dataSource.GetType()是否等于您尝试将其投射到的类型。

答案 9 :(得分:0)

如果使用as,则不会有运行时InvalidCastException,但表可能为null,因此您需要检查它。

答案 10 :(得分:0)

使用as和普通强制转换之间的区别在于,如果无法执行强制转换(因为对象不是正确的类型),as运算符将返回{{1 }}。正常演员会抛出异常。

所以他们都“安全” - 当演员阵容无法成功时,他们只会有不同的行为。