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

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

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

有更安全的铸造方式吗?

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

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

如果您的系统中存在不良数据,那么继续好像一切都很好是危险的路径,而不是安全路径。 这就是你需要的方式,而一个演员会抛出一个InvalidCastException ,在你有机会对坏数据造成混乱之前中止你所做的一切。

如果它对于不属于给定类型的对象有效 – 如果它不表示错误那么好。 你几乎总能看到以下模式:

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

有关详细信息,请参阅MSDN 。

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

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

您可能知道,在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 

不同之处在于,如果运行时不知道如何将myObjectMyType ,则第一行将抛出exception,而第二行仅将foo设置为null 。 如果生成在myObject的对象不是MyType ,或者没有myObject的任何显式转换为MyType ,则会发生这种情况。

哪一个更安全? 好吧,如果“安全”意味着“如果演员表无效则不会抛出exception”,则表格更安全。 如果转换失败, (MyType)myObject将立即爆炸,但myObject as MyType只会在你尝试做某些事情时才会爆炸,你不能做null (比如调用foo.ToString() )。

另一方面, 有时抛出exception是最安全的事情。 如果您的代码中有错误,您可能想立即知道。 如果myObject总是被期望是MyType ,那么失败的MyType意味着某处存在错误。 如果你继续进行铸造工作,那么你的程序会突然处理垃圾数据! 它可能会进一步爆炸,使调试变得困难,或者 – 更糟糕 – 它可能永远不会爆炸,只是悄悄地做你没想到的事情。 这可能会造成各种各样的破坏。

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

  1. 你不确定myObject是什么类型的
  2. 您想对myObject执行某些操作,但myObject是它的类型为MyType
  3. myObject可能不是MyType ,它并不意味着有一个bug

一个例子是当你有一组不同的WebForm控件时,你想要清除它们中的所有TextBox:

 foreach (var control in controls) { var textbox = control as TextBox; if (textbox != null) { //Now we know it's a TextBox, so we know it has a Text property textbox.Text = string.Empty; } } 

这样,你的TextBox就会被清除掉,其他一切都会被遗忘。

 DataTable table = dataSource as DataTable; 

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

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

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

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

这基本上就是你需要做的事情:

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

要么

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

如果这是“安全”的意思,它不会抛出exception。 但是,如果转换失败,则table将为null。

 DataTable table = dataSource as DataTable; 

如果强制转换失败,则不会抛出exception。 将为null。

 DataTable table = (DataTable)dataSource; 

如果转换失败,将抛出exception。

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

这是一种安全的方式来表明它不会导致exception。 但是,如果您不小心,它可能会导致隐藏的错误。

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

取决于你想要做的事情:

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

意味着“ dataSource 可能是一个DataTable ,我将检查它不是null 。”

 DataTable table = (DataTable) dataSource; 

意味着“ dataSource 绝对应该是一个DataTable ,如果不是,那就是错误的”。

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

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

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

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