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


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

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

有更安全的铸造方式吗?


22
2018-06-17 16:11


起源


你更安全的意思是什么? - Felice Pollano
为什么dataSource由ref传递? - Eric Lippert
@Eric Lippert:dataSource(以及表格)用于连接代理。我觉得应该传递地址而不是价值..(如果我理解参考点和代表的话)...... - developer
你为什么这么想?你有没有改变dataSource别名的变量?这就是“ref”的要点 - 为变量创建一个别名,以便你可以改变它。 - Eric Lippert
@Felice:我假设如果dataSource不是一个表,它会在现场爆炸。 (我只是想知道是否有一种方法它不会爆炸)但是现在从答案中我意识到它只会返回null(这比炸毁更好?:)。 - developer


答案:


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

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

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

as 如果它是好的 有效 对象不是给定类型 - 如果它不表示错误。您 几乎总是 看模式:

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

看到 MSDN 有关什么的更多细节 as 确实。

还要注意你 大概 不想用 ref 在你的方法。看我的 关于参数传递的文章 更多细节。大多数时候,如果我看到人们使用 ref 很多,这是因为他们不明白它的真正含义:)


36
2018-06-17 16:14



谢谢您的回答! (在我决定答案之前,我需要阅读所有这些内容)至于参数..我正在使用dataSource(以及表格)来连接代理: table.RowChanged += new DataRowChangeEventHandler (handler.DataChanged); 这不应该是ref(c ++中的指针类型)吗?我认为它应该指向地址,而不仅仅是给数据表赋值。但如果我错了......请告诉我:D - developer
@developer:基本上阅读我链接的文章。 “参考”和“通过参考传递参数”之间存在很大差异。 别 用C ++来思考 - 当你编写C#时,它会让你感到困惑。 - Jon Skeet
好的谢谢:)我会读它。 - developer
@Jon:我读了你的文章,然后我也读了 rapidapplicationdevelopment.blogspot.com/2007/01/...  - 这帮了很多忙!我还是想用 ref..我希望它像图#7一样工作..(因为如果我像图#5那样实现它,将传递的var设置为null将不会改变原始的var ..我认为这对于能够做)。 - developer
@developer:而不是使用 ref,考虑引入一个回报值。这是一般的 许多 比使用更清楚 ref。 - Jon Skeet


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

您可能知道,在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 至 null。如果对象存在,就会发生这种情况 myObject 不是 MyType,或者如果没有明确的演员表 MyType 无论如何 myObject 是。

哪一个更安全?好吧,如果“安全”意味着“如果演员阵容无效则不会抛出异常”,那么 as 形式更安全。如果铸造失败, (MyType)myObject 会立刻爆炸,但是 myObject as MyType 只有你试图做某事才会爆炸 foo 那是你做不到的 null (比如打电话 foo.ToString())。

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

因此,这两种形式都不是本质上安全或正确的,它们只适用于不同的事物。你会用的 myObject as MyType 表格如果:

  1. 你不确定是什么类型 myObject 是
  2. 你想做点什么 myObject,但只有它的类型 MyType
  3. myObject 可能是除了之外的东西 MyType,这并不意味着有一个错误

一个例子是当你有一组不同的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就会被清除掉,其他一切都会被遗忘。


11
2018-06-17 16:29





DataTable table = dataSource as DataTable;

运用 as 将返回 null 如果演员阵容不成功,那么它不会爆炸。 - 这意味着你必须处理这种情况 table 是 null 但是在你的其余代码中。


5
2018-06-17 16:14





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

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

4
2018-06-17 16:14





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

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

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

要么

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

2
2018-06-17 16:13





如果这是“安全”的意思,它不会抛出异常。但是,如果演员表失败, table 将为null。

DataTable table = dataSource as DataTable;

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

DataTable table = (DataTable)dataSource;

如果转换失败,将抛出异常。

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


2
2018-06-17 16:15





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

使用时 as,如果转换失败,那么结果变量是 null。如果你没有检查这个,那么你以后会得到一个 NullReferenceException 当你试图访问变量时,它将不清楚它为什么失败(例如它 null 因为演员表失败或后来做了别的事情导致它为null


2
2018-06-17 16:14





取决于你想要做的事情:

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

意思是“dataSource  威力 是一个 DataTable 我要检查它不是 null“。

DataTable table = (DataTable) dataSource;

意思是“dataSource 应该 无疑 是一个 DataTable 如果它不是“,那就是错误的。”


1
2018-06-17 16:14





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


0
2018-06-17 16:14





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


0
2018-06-17 16:14