2011-03-22 86 views
1

也许这是早上刚刚太早,我是一个傻瓜,但我是一个有点困惑这个....使用'as'投射 - 为什么这不起作用?

SqlCommand cmd = new SqlCommand("prc_FooBar", conn)); 
object obj = cmd.ExecuteScalar(); 

// this is fine 
decimal? d = (decimal?)(obj as double?); 

// this doesn't compile 
decimal? d = (obj as double?) as decimal?; 

为什么不上一个版本编译?

+0

你得到的错误是什么?也是第一行是好的,它没有给出运行时异常执行吗? – 2011-03-22 09:48:44

+2

我的编译器(4.0)不同意你在第二个“这很好” – 2011-03-22 09:50:16

+0

是的抱歉,这是一个错误,我编辑 – fearofawhackplanet 2011-03-22 09:56:12

回答

6

as运算符与演员表不一样。此博客解释:

http://blogs.msdn.com/b/csharpfaq/archive/2004/03/12/what-s-the-difference-between-cast-syntax-and-using-the-code-as-code-operator.aspx

它仅在同一层级的“casts”类型之间,基本上遵循了“是”的想法。 A decimal?不是double?,但是编译器可能会诱使您认为它可能是因为它在您丢失信息时明确为您转换它的时候生成(decimal?)myDouble;as运营商不会为您这样做,从而失败。

更新:你问为什么有一个编译器错误,而不是空结果。这是因为as运营商永远不可能得到double?decimal?。尝试:

string s = ""; 
MyClass f = s as MyClass; 

开箱即用,这是行不通的,因为编译器知道这一点。得到编译器错误比较好,因为它无法在当前状态下工作。

在正常使用情况下,如果类型实际上是您认为的类型,则可以使用as运算符将强制类型转换为派生类型。然而,该类型可以是另一种派生类型(此编译):

MyBase b = new MyDerived1(); 
MyDerived2 d = b as MyDerived2(); 

虽然技术上编译器可以知道这(在某些情况下),如果它不将其与空,如果转换失败响应。

我敢肯定有人要一起去,并告诉我,我是多么的错误是:-)

+0

但为什么它是一个错误,而不是只解决'空'? (查看我对Jon Hanna的评论) – fearofawhackplanet 2011-03-22 10:17:14

+0

我已经更新了我的答案。 – 2011-03-22 10:33:27

3

docs

...的运营商只执行基准转换和装箱转换。

double?转换为decimal?不适合这两种类别,因为没有拳击去,double?是不是一个亚型或decimal?超。

+0

因为他使用小数?作为类型,它实际上是一个引用类型:可为空。 – Aidiakapi 2011-03-22 09:56:37

+2

@Aidiakapi:'可为空'是* not *引用类型,尽管编译器允许可以在某些方式中模仿ref类型的行为。 http://msdn.microsoft.com/en-us/library/b3h38hb0.aspx – LukeH 2011-03-22 10:05:22

+0

@LukeH,感谢纠正我,有人告诉我,这是我认为是谁的原因。 – Aidiakapi 2011-03-22 10:08:27

1

var x = v as X等同于:

var v = v is X ? (X)v : null;但只有单一类型的检查操作发生((X)v自己检查v是否或可以转换为X,否则抛出异常)。

double? tmp = obj is double? ? (double?)obj : null; 
decimal? d = tmp is decimal? ? (decimal?)tmp : null; 

它在编译时真实已知tmpdouble?(具有一个值,或者没有值使它等于null):以

你的后一种情况下是相等的。因此tmp is decimal?的测试总是错误的,并且在编译时操作失败。

+0

这是一个非常明确的解释,谢谢。这种行为似乎很奇怪,但......你似乎在说“双重”的唯一原因?作为十进制?'是编译时错误是因为编译器确定结果将始终为空,但是我可以愉快地将'null作为十进制?'写入而不出错。 – fearofawhackplanet 2011-03-22 10:17:40

+0

'as'旨在用于投射,因此有人试图做不可能的投射可能有一个错误。编译器已经救了你,因为如果它每次只给null赋值d就很难找到并修复它。 – 2011-03-22 10:21:06