“as”运算符的意外行为,它与普通强制转换不同

2024-02-09

I asked 这个问题 https://stackoverflow.com/questions/21432141/why-i-cannot-cast-derived-generic-type-to-base-non-generic-type-through-a-const。此代码无法编译(“无法转换Generic<T> to T")因为解释的原因here https://stackoverflow.com/a/21432252/1207195(即使我期望InvalidCastException在运行时代替编译时错误)。

class NonGeneric
{
}

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

接受的解决方案提供了此解决方法:

T DoSomething()
{
    return this as T;
}

我的问题是:why? as运算符应该与强制转换运算符完全相同:

as 运算符类似于强制转换操作。但是,如果无法进行转换,as 将返回 null 而不是引发异常。

If this as T应该等于this is T? (T)this: (T)null那么为什么as T作品和(T)this甚至无法编译? AFAIKcast 的使用范围比as:

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

那为什么会这样呢?这是一个已记录的功能吗as操作员?这是泛型类型的编译器/语言限制吗?请注意,此代码编译良好:

return (T)((object)this);

这是因为编译器无法确定是否T is dynamic(即使有一个where约束)那么它总是会生成这样的代码?


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

如果 E 的编译时类型不是动态的,则 E as T 操作会产生与以下相同的结果 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必须是引用类型、已知为引用类型的类型参数或可为 null 的类型。此外,至少以下之一必须为真,否则会发生编译时错误:

• 标识(§6.1.1)、隐式可为空(§6.1.4)、隐式引用(§6.1.6)、装箱(§6.1.7)、显式可为空(§6.2.3)、显式引用(§6.2) .4),或拆箱(§6.2.5)转换存在于E to T.

的类型E or T是开放式的。

E is the null文字。

这是您的泛型类的当前情况。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

“as”运算符的意外行为,它与普通强制转换不同 的相关文章

随机推荐