使用'as'进行投射 - 为什么这不起作用?

时间:2011-03-22 09:47:20

标签: c# ado.net casting type-conversion

也许现在早上太早了,我是个白痴,但我对此感到有些困惑....

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?; 

为什么最后一个版本不能编译?

3 个答案:

答案 0 :(得分: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

它只在同一层次结构中的类型之间“强制转换”,基本上遵循“is-a”的想法。 decimal?不是double?,但是编译器会诱使您认为它可以在(decimal?)myDouble;时出现,因为它会在丢失信息时为您明确地投射它。 as运算符不会为您执行此操作,因此会失败。

更新:您问为什么存在编译器错误而不是null结果。这是因为as运算符永远无法将double?传递给decimal?。尝试:

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

开箱即用,这不起作用,因为编译器知道这一点。最好得到一个编译器错误,因为它永远不能在它的当前状态下工作。

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

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

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

我确定有人即将到来告诉我我有多错: - )

答案 1 :(得分:3)

来自docs

  

... as 运算符仅执行引用转换和装箱转换。

double?转换为decimal?不符合这两个类别,因为没有装箱,double?不是decimal?的子类型或超类型}。

答案 2 :(得分: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?的测试始终为false,并且在编译时操作失败。