在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
不同之处在于,如果运行时不知道如何将myObject
为MyType
,则第一行将抛出exception,而第二行仅将foo
设置为null
。 如果生成在myObject
的对象不是MyType
,或者没有myObject
的任何显式转换为MyType
,则会发生这种情况。
哪一个更安全? 好吧,如果“安全”意味着“如果演员表无效则不会抛出exception”,则表格更安全。 如果转换失败, (MyType)myObject
将立即爆炸,但myObject as MyType
只会在你尝试做某些事情时才会爆炸,你不能做null
(比如调用foo.ToString()
)。
另一方面, 有时抛出exception是最安全的事情。 如果您的代码中有错误,您可能想立即知道。 如果myObject
总是被期望是MyType
,那么失败的MyType
意味着某处存在错误。 如果你继续进行铸造工作,那么你的程序会突然处理垃圾数据! 它可能会进一步爆炸,使调试变得困难,或者 – 更糟糕 – 它可能永远不会爆炸,只是悄悄地做你没想到的事情。 这可能会造成各种各样的破坏。
因此,这两种forms都不是本质上安全或正确的,它们只适用于不同的事物。 如果出现以下情况,您可以使用myObject as MyType
表单:
- 你不确定
myObject
是什么类型的 - 您想对
myObject
执行某些操作,但myObject
是它的类型为MyType
-
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
,因此不会爆炸。 – 这意味着您必须处理代码的其余部分table
为null
的情况。
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。
所以他们都“安全” – 当演员阵容无法成功时,他们只会有不同的行为。