Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/google-cloud-platform/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 当您可以使用“时,为什么要强制转换引用类型?”;“作为”吗;?_C#_Casting - Fatal编程技术网

C# 当您可以使用“时,为什么要强制转换引用类型?”;“作为”吗;?

C# 当您可以使用“时,为什么要强制转换引用类型?”;“作为”吗;?,c#,casting,C#,Casting,可能重复: 在C#中,既然可以使用“as”,为什么还要强制转换引用类型 强制转换可以生成异常,而如果强制转换失败,“as”将计算为null 在所有情况下,“as”不是更容易与引用类型一起使用吗 例如: 而不是 (DataGridView)MyObject 运算符“as”仅用于引用类型。有时,您希望抛出异常。有时,您需要尝试转换,空值也可以。如前所述,As不适用于值类型。来自MSDN(): as运算符仅执行引用转换和装箱转换。as运算符不能执行其他转换,例如用户定义的转换,而应使用强制转换表达

可能重复:

在C#中,既然可以使用“as”,为什么还要强制转换引用类型

强制转换可以生成异常,而如果强制转换失败,“as”将计算为
null

在所有情况下,“as”不是更容易与引用类型一起使用吗

例如:

而不是

(DataGridView)MyObject

运算符“as”仅用于引用类型。

有时,您希望抛出异常。有时,您需要尝试转换,空值也可以。如前所述,
As
不适用于值类型。

来自MSDN():

as运算符仅执行引用转换和装箱转换。as运算符不能执行其他转换,例如用户定义的转换,而应使用强制转换表达式执行这些转换


考虑到所有的评论,我们前几天遇到了这个问题,想知道为什么您要使用关键字
as
进行直接转换。如果你想让演员失败怎么办?如果从空对象进行强制转换,这有时是您希望从强制转换中获得的理想效果。然后将异常推送到调用堆栈上


因此,如果您想让某些内容失败,请使用直接强制转换,如果您对它没有问题,请使用
作为
关键字。

如果在编写代码进行强制转换时,您确信强制转换可以工作,则应使用
(DataGridView)MyObject
。这样,如果将来强制转换失败,您对MyObject类型的假设将在进行强制转换时导致无效的强制转换异常,而不是在以后某个时候导致空引用异常

如果您确实想处理MyObject不是DataGridView的情况,那么使用
作为
,并在使用它之前检查它是否为null


tl;dr如果您的代码假设了某些东西,并且该假设在运行时是错误的,那么代码应该抛出异常。

考虑以下备选方案:

Foo(someObj as SomeClass);
以及:

由于someObj的类型错误,第一个版本将
null
传递给
Foo
。一段时间后,这会导致抛出
NullReferenceException
。多久以后?取决于
Foo
的功能。它可能会将
null
存储在一个字段中,然后几分钟后,一些代码会访问它,这些代码希望它是非
null

但是对于第二个版本,您会立即发现问题

为什么要让修复bug变得更加困难

更新

OP在一条评论中问道:将
用作
并在
if
语句中检查
null
是否更容易

如果
null
是意外的,并且是调用者中存在错误的证据,您可以说:

SomeClass c = someObj as SomeClass;
if (c == null)
{
    // hmm...
}
if
-块中,您会做什么?有两种通用解决方案。一种是抛出异常,因此处理错误是调用方的责任。在这种情况下,写以下内容肯定更简单:

SomeClass c = (SomeClass)someObj;
它只需手动编写
if
/
抛出
逻辑即可

不过,还有另一种选择。如果您有一个
SomeClass
的“stock”实现,您很乐意在没有更好的方法可用的情况下使用它(可能它的方法不做任何事情,或者返回“空”值等),那么您可以这样做:

SomeClass c = (someObj as SomeClass) ?? _stockImpl;
这将确保
c
永远不会
null
。但这真的更好吗?如果来电者有bug怎么办;你不想帮忙找虫子吗?通过在默认对象中交换,可以隐藏错误。这听起来是个很有吸引力的主意,直到你浪费了一周的时间去寻找一个bug


(在某种程度上,这模仿了Objective-C的行为,在这种行为中,任何尝试使用
null
引用的行为都不会抛出;它只是默默地不做任何事情。)

一个明确的原因是,对象正在或可能(在编写泛型方法时,您可能在编码时不知道)被转换为值类型,在这种情况下,不允许使用
as

另一个可疑的原因是,您已经知道该对象属于所讨论的类型。怀疑的程度取决于你是如何知道的。在下列情况下:

if(obj is MyType)
  DoMyTypeStuff((MyType)obj);
else
  DoMoreGeneralStuff(obj);
这里很难证明使用
作为
是合理的,因为它真正做的唯一一件事就是添加一个冗余检查(可能会被优化掉,可能不会)。在另一个极端,如果你处于恍惚状态的一半,你的大脑中有大量的信息在记忆中被分页,基于此,你非常确定这个对象一定是有问题的类型,也许最好在支票中加上

另一个很好的原因是,类型错误和为null之间的差异被
隐藏为
。如果将字符串传递给给定的方法(包括空字符串)是合理的,但传递int是不合理的,那么
val as string
只会使错误用法看起来像是完全不同的正确用法,而您只会使错误更难发现,并且可能更具破坏性


最后,如果您不知道对象的类型,调用代码应该是。如果调用代码错误地调用了您的代码,则他们将收到异常。允许InvalidCastException传回,或者捕获它并抛出InvalidArgument异常或类似异常,这是一种合理而清晰的方法。

As更快且不会抛出异常。因此,它通常是首选的。使用强制转换的原因包括:

使用as,只能将继承树中较低的类型分配给较高的类型。例如:

object o = "abc" as object;
DataGridView d = "abc" as DataGridView // doesn't do anything
DataGridView可以创建一个自定义的强制转换来实现这一点。强制类型转换是在目标类型上定义的,因此只要定义了它,就允许一切

as的另一个问题是,它并不总是有效的
if(obj is MyType)
  DoMyTypeStuff((MyType)obj);
else
  DoMoreGeneralStuff(obj);
object o = "abc" as object;
DataGridView d = "abc" as DataGridView // doesn't do anything
IEnumerable<T> GetList<T>(T item)
{
  (from ... select) as IEnumerable<T>
}