勇哥注:
今天突然发现强制类型转换和as还是有点区别的。
比如下面这句会抛异常:
其中SACItemRunStatusEnum是一个枚举。
ItemRunStatus= (Tuple<SACItemRunStatusEnum, int>)data
异常信息如下:
无法将类型为 “System.Tuple`2[Samsun.Domain.MotionCard.Common.SACItemRunStatusEnum,System.Object]” 的对象强制转换为类型 “System.Tuple`2[Samsun.Domain.MotionCard.Common.SACItemRunStatusEnum,System.Int32]”。
但是写成as就好了
ItemRunStatus= data as Tuple<SACItemRunStatusEnum, int>;
这是什么原因呢?
所以在网上查了一些资料,先放这,有时间再研究一下为啥。
2023/3/2勇哥注:
今天突然发现我上面的回答是误人子弟。
ItemRunStatus= data as Tuple<SACItemRunStatusEnum, int>; 这种转换看上去是成功了,但是结果确是null.
因此,实际本文的关键内容是“如何把object转为一个Tuple”。
在实时窗口里,敲入object变量data,可以看到是有内容的。
既然强制转换和as转换都不行,还有什么办法取出这个Item1和Item2呢?
如下图所示就可以了!!
但是它们取出的是字符串类型,因此还得转换一下。
如下:
ItemRunStatus =new Tuple<SACItemRunStatusEnum, int>( (SACItemRunStatusEnum)Enum.Parse(typeof(SACItemRunStatusEnum),data.GetType().GetProperty("Item1").GetValue(data, null).ToString()), int.Parse(data.GetType().GetProperty("Item2").GetValue(data, null).ToString()) );
这个问题在网上是无解的,因为没有人问到过这个问题。
下面是网上的一些资料,关于强制转换与as的区别:
=========================================
What is the difference between casting and using “as” in C#?
如果存在差异,那么进行以下转换的两种方式之间有什么区别?
在这种情况下,
1 2 3 | GridView gv = (GridView)e.Row.FindControl("gv"); //first way GridView gv2 = e.Row.FindControl("gv") as GridView; //second way |
不同之处在于:
如果强制转换失败,则会抛出
InvalidCastException 。
如果
as 运算符失败,则仅返回空引用。
您不能将
as 与不可为空的值类型一起使用(例如,不能执行"
o as int ")。
强制转换运算符还用于取消装箱。 (
as 可用于取消装箱为可为空的值类型。)
强制转换运算符还可以执行用户定义的转换。
编辑:我已经在其他地方写过有关何时适合使用哪个运算符的文章。可能值得一读...
让我用引用类型更新代码Jon。
不需要太多-我已经在我的回答中解释了更多:)
非常感谢,我实际上确实使用GridView更新了它,但是您的回答足够好。
有几个问题,as运算符是实际的转换吗?一个比另一个快吗?
我建议将问题改回不可为空的类型,因为现在,初次阅读时答案令人困惑。
@Paul:我会改正答案。 @Xaisoft:它们基本上彼此一样快。
另一个显着差异-as运算符比强制转换运算符快得多。
我将添加一个链接,因为它似乎在呼唤Jon Skeet,这很危险。 stackoverflow.com/questions/57701/
@不确定:我对此表示怀疑。请提供证据。请注意,使用" as"和空检查比执行" is"和强制类型转换要快,但这与说" as"比强制类型转换要快得多。
@不确定:如果强制转换肯定会引发异常,则执行转换会较慢,但在成功的情况下,它们基本上是相同的。另请注意,链接的答案准确地说出我对" is + cast"的处理要比" as + null check"慢。它没有说在"按原样/按铸造"成功案例中哪个更快。
@Jon Skeet:查找您上面提到的用户转换的成本为非零,只有前缀强制转换为零,并且是"成功"。我同意,在实例已经是强制转换类型的情况下,它们应该执行相同的操作,但这仅是一个用例。
@不确定:否,寻找用户转换的成本是在编译时完成的。
我不是在谈论实例是实际强制类型的琐碎情况,而是在谈论任何"成功"方案。鉴于故障场景的结果是如此不同(无论是否引发异常),我认为比较那里的性能并不明智。
回到用户定义的转换:如果C#编译器发出" castclass"指令而不是调用op_Explicit或op_Implicit,则转换将失败。我有一个测试应用程序,如果您想查看它,可以演示此过程。
@Jon Skeet-我不同意,比较这些不同的转换方法的性能非常明智,因为它们可以并且通常用于运行时类型检查的相同目的。
@Jon Skeet-顺便说一句,您似乎在这里与自己矛盾:blogs.msdn.com/csharpfaq/archive/2004/03/12/88420.aspx。"与铸造相比,在Microsoft CLR的v1.0和v1.1中,as运算符似乎要快一些,"除非以后的CLR版本中有所更改。
@不确定:我很确定它已经改变了。无论哪种方式,按照您最初的主张,它肯定不会"显着更快"。如果您愿意,我们可以对其进行基准测试。
@不确定:如果目的只是为了检查执行时间,那么您当然不应该进行强制转换,然后大概捕获异常。那太疯狂了。如果您只想检查,请使用"是"。如果要检查然后使用新类型的值,请使用" as",然后使用空检查。
如果要使用新类型,并且想要异常类型错误的异常(因为这表明您的情况在某些代码中存在错误),请使用强制转换。对我来说似乎很简单。
@Jon Skeet:争论不是关于哪种用例的适当性,而是关于特定用例下的性能差异,这是通常的做法,无论您和我是否更了解。
仅当结果相同时才比较性能。我不认为Xaisoft询问哪个更快时,他询问的是失败案例。显而易见,异常比返回null慢。
因此,您是否声称当强制转换和" as"都成功(即返回非空引用)时," as"要快得多?
在我的原始帖子中大量使用形容词是错误的,但仍然比前缀更快。 用您的话来说,CLR 1.0 / 1.1的区别很小。 我用3.5进行的测试表明差异仍然存在,但可以忽略不计。 谷歌搜索" C#铸造性能"证实了这一点。
好的,我对此很满意。 我当然不会对"它更快但只有一点点"提出异议。"显着"给人错误的印象。 我松了一口气,看到我本来就允许自己有一些回旋余地,说他们彼此之间"快" :)
上面的答案中没有提到的是目的-为什么要执行转换,(更重要的是)转换后的行会发生什么?
例如,我多次看到类似于以下代码的代码:
if ((foo as SomeType).SomeMethod()) { /* ... */ }
可以将其与使用强制转换的版本进行比较:
if (((SomeType) foo).SomeMethod()) { /* ... */ }
那么,哪个更好?
演员是。
如果转换失败,则使用
如果转换失败,则使用强制类型转换将导致
现在告诉我,哪个是调试更有用的例外?
因此,仅当转换实际上是可选的时才使用
安全投为
1 | variable as type |
与...相同
1 |
并且不适用于值类型。
" as"语句基本上会尝试转换该变量,如果失败则返回null而不是引发异常。因此,您要强制转换为的值必须可以为空-引用类型或可为空的原语。在您的示例中,您必须执行以下操作:
1 | int? i2 = o as int; |
否则将无法编译。
通常,静态类型转换与" as"之间的区别在于,如果转换失败,则类型转换将引发Exception,而" as"仅将变量设置为null。
除了Jon指出的问题外,
1 | SomeClass i2 = o as SomeClass; |
变
1 2 3 4 5 |
但是,如果您使用引用类型,则说Table,则第一个将引发InvalidCastException,以防无法将o分配给Table,而第二个将仅返回null。
我可能会在这里说明显而易见的内容,但是使用" as"强制转换可以得到的一件事是,可以确保最终得到您请求的类型的对象。
在某些情况下这很方便。

