“ as”的意外行为运算符,与普通转换不同 [英] Unexpected behavior of "as" operator, it differs from plain cast
问题描述
我问这个问题。此代码无法编译(无法将 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 andT
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屋!