“ as”的意外行为运算符,与普通转换不同 [英] Unexpected behavior of "as" operator, it differs from plain cast

查看:49
本文介绍了“ as”的意外行为运算符,与普通转换不同的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我问这个问题。此代码无法编译(无法将 Generic< T> 转换为 T ),原因是在此处解释的原因(即使我希望 InvalidCastException 在运行时而不是编译时错误)。

I asked this question. This code doesn't compile ("Cannot convert Generic<T> to T") because of the reason explained here (even if I'd expect an InvalidCastException at run-time instead of a compile-time error).

class NonGeneric
{
}

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

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

Accepted solution gave this workaround:

T DoSomething()
{
    return this as T;
}

我的问题是:为什么 as 运算符应与强制转换运算符完全相同:

My question is: why? as operator should be exactly equivalent to cast operator:


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

The as operator is like a cast operation. However, if the conversion isn't possible, as returns null instead of raising an exception.

如果 this因为T 应该等于这是T? (T)this:(T)null 然后为什么 as T 起作用而(T)this 甚至不编译?与 as 相比,AFAIK转换可以在更广泛的情况下使用:

If this as T should be equivalent to this is T? (T)this: (T)null then why as T works and (T)this doesn't even compile? AFAIK cast could be used in a more wide range of situations than as:


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

Note that the as operator performs only reference conversions, nullable conversions, and boxing conversions. The as operator can't perform other conversions, such as user-defined conversions, which should instead be performed by using cast expressions.

那为什么呢?它是 as 运算符的记录功能吗?它是通用类型的编译器/语言限制吗?请注意,这段代码可以很好地编译:

Then why this? Is it a documented feature of as operator? Is it a compiler/language limitation with generic types? Note that this code compiles fine:

return (T)((object)this);

这是因为编译器无法确定 T 动态(即使存在 where 约束),那么它总是会生成这样的代码吗?

Is this because compiler can't be sure if T is dynamic (even if there is a where constraint) then it'll always generate such code?

推荐答案

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

It says in the C# Language Specification (emphasis mine),


如果E的编译时类型不是动态的,则操作E作为T产生的结果与
E为T的结果相同? (T)(E):(T)null
,除了E仅被评估一次。可以期望编译器将E优化为T,以最多执行一个动态类型检查,而不是上述扩展所隐含的两个动态类型检查。

If the compile-time type of E is not dynamic, the operation E as T produces the same result as E is T ? (T)(E) : (T)null except that E is only evaluated once. The compiler can be expected to optimize E as T to perform at most one dynamic type check as opposed to the two dynamic type checks implied by the expansion above.

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

If the compile-time type of E is dynamic, unlike the cast operator the as operator is not dynamically bound (§7.2.2). Therefore the expansion in this case is: E is T ? (T)(object)(E) : (T)null

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

This seems to be the reason why the compilation succeed using as or when this is cast to an object first. Furthermore,


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

In an operation of the form E as T, E must be an expression and T must be a reference type, a type parameter known to be a reference type, or a nullable type. Furthermore, at least one of the following must be true, or otherwise a compile-time error occurs:

•身份(第6.1.1节),隐含可空值(第6.节) 6.1.4),隐式引用(§6.1.6),装箱(§6.1.7),显式可为空(§6.2.3),显式引用(§6.2.4)或拆箱(§6.2.5)转换存在从 E T

• An identity (§6.1.1), implicit nullable (§6.1.4), implicit reference (§6.1.6), boxing (§6.1.7), explicit nullable (§6.2.3), explicit reference (§6.2.4), or unboxing (§6.2.5) conversion exists from E to T.

E T 的类型是开放类型。

The type of E or T is an open type.

E null 文字。

泛型类的当前情况。

这篇关于“ as”的意外行为运算符,与普通转换不同的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆