“as”运算符的意外行为,它与plain cast不同

时间:2014-01-29 13:32:34

标签: c# .net casting

我问this question。此代码无法编译(“无法将Generic<T>转换为T),因为解释here的原因(即使我期望{{3}} 1}}在运行时而不是编译时错误。)

InvalidCastException

接受的解决方案给出了解决方法:

class NonGeneric
{
}

class Generic<T> : NonGeneric
    where T : NonGeneric
{
    T DoSomething()
    {
        return (T)this; // ** Cannot convert...
    }
}

我的问题是:为什么T DoSomething() { return this as T; } 运算符应完全等同于强制运算符:

  

as运算符就像一个强制转换操作。但是,如果无法进行转换,则返回null而不是引发异常。

如果as应该等同于this as T那么为什么this is T? (T)this: (T)null有效且as T甚至无法编译? AFAIK演员阵容可用于比(T)this更广泛的情况:

  

请注意,as运算符仅执行引用转换,可空转换和装箱转换。 as运算符无法执行其他转换,例如用户定义的转换,而应使用强制转换表达式执行转换。

那为什么呢?它是as运算符的文档功能吗?它是泛型类型的编译器/语言限制吗?请注意,此代码编译良好:

as

这是因为编译器无法确定return (T)((object)this); 是否为T(即使存在dynamic约束),那么它是否会始终生成此类代码?

3 个答案:

答案 0 :(得分:5)

根据msdn: -

  

as运算符就像一个强制转换操作。但是,如果无法进行转换,则返回null而不是引发异常

     

代码等同于以下表达式,只是表达式变量只被计算一次。

    expression is type ? (type)expression : (type)null

另一个不同之处在于: -

  

请注意,as运算符仅执行引用转换,可空转换和装箱转换。 as运算符无法执行其他转换,例如用户定义的转换,而应使用强制转换表达式执行转换。

答案 1 :(得分:5)

它在C#语言规范(强调我的)中说,

  

如果E的编译时类型不是动态的,则作为T的操作E产生与之相同的结果   E是T? (T)(E):( T)无效   除了E只评估一次。可以期望编译器将E优化为T以执行最多一次动态类型检查,而不是上面扩展所暗示的两种动态类型检查。

     

如果E的编译时类型是dynamic ,则与强制转换运算符不同,as运算符不是动态绑定的(第7.2.2节)。因此,在这种情况下的扩展是:   E is T ? (T)(object)(E) : (T)null

这似乎是编译使用as成功或首先将this强制转换为对象的原因。此外,

  

E as T形式的操作中,E必须是表达式,T必须是引用类型,已知为引用类型的类型参数或可空类型。此外,必须至少满足下列条件之一,否则会发生编译时错误:

     

•标识(第6.1.1节),隐式可空(第6.1.4节),隐式引用(第6.1.6节),装箱(第6.1.7节),显式可空(第6.2.3节),显式引用(§6.2.4)或从ET的拆箱(§6.2.5)转换。

     

ET的类型是开放式。

     

Enull字面值。

您的通用类的当前案例。

答案 2 :(得分:-5)

'as'作为C#中的运算符执行以下操作: -

  1. 如果给定变量不是任何基类型的给定类型,则返回null。它不会抛出任何异常
  2. 只能应用参考类型变量。
  3. 'as'不进行任何转换(隐式/显式)
  4. 'as'运算符比任何一个转换都快一些(即使在没有无效转换的情况下,由于异常会严重降低转换的性能)。