gpt4 book ai didi

c# - 当右侧操作数是泛型时, "as"运算符如何翻译?

转载 作者:可可西里 更新时间:2023-11-01 03:01:31 26 4
gpt4 key购买 nike

我刚刚发布了一个 answerthis question但我并不完全相信我的回答。有两件事我想知道,请考虑这段代码:

class Foo<T>
{
void SomeMethod()
{
string str = "foo";
Foo<T> f = str as Foo<T>;
}
}

根据 C# Specification 5.0 , as operator 有两种不同的转换方式.

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

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

由于(Foo<T>)str,这是无效的

str is Foo<T> ? (Foo<T>)str : (Foo<T>)null;

我觉得应该翻译成:

str is Foo<T> ? (Foo<T>)(object)str : (Foo<T>)null;

但是规范说这只发生在 E 的类型时是dynamic .

所以我的问题是:

  1. 编译器是否将此表达式转换为通常无效的代码?
  2. E 的类型时是动态的,为什么它首先转换 Eobject然后T(T)E是完全有效的吗?

最佳答案

Is the compiler translating this expression to a code that is normally invalid?

在盯着规范看了大约一个小时之后,我开始说服自己这只是规范中被忽视的一个边缘案例。请注意,这只是 C# 语言编写者用 is 运算符的语义表达 as 运算符的一种方式。

编译器实际上并不as 运算符转换为带有is 的三元运算符。它将发出对 isinst 的 IL 调用,包括 asis:

IL_0000: nop
IL_0001: ldstr "foo"
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: isinst class ConsoleApplication2.Foo`1<!T>
IL_000d: stloc.1
IL_000e: ret

查看已编译的 DLL,as 运算符保持不变。

When the type of E is dynamic why first it casts E to object then T while the (T)E is completely valid?

这在规范的细则中有描述:

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

需要转换为object 才能使asdynamic 对象一起使用。 as 是一个编译时 操作,而动态 对象仅在运行时 绑定(bind)。

编译器实际上将 dynamic 类型对象视为类型 object 以开始:

class Foo<T> 
{
public void SomeMethod()
{
dynamic str = "foo";
Foo<T> f = str as Foo<T>;
}
}

str 实际上被视为 object 开始于:

.class private auto ansi beforefieldinit Foo`1<T>
extends [mscorlib]System.Object
{
// Methods
.method public hidebysig
instance void SomeMethod () cil managed
{
// Method begins at RVA 0x2050
// Code size 15 (0xf)
.maxstack 1
.locals init (
[0] object,
[1] class Foo`1<!T>
)

IL_0000: nop
IL_0001: ldstr "foo"
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: isinst class Foo`1<!T>
IL_000d: stloc.1
IL_000e: ret
} // end of method Foo`1::SomeMethod
}

编辑:

在与托管语言团队的 Vladimir Reshetnikov 交谈后,他解释了从“as operator”到“cast operator”的表示语义实际上试图表达什么:

I agree, there is some imprecise language in the spec too. It says 'as' operator is always applicable if an open type involved, but then describes its evaluation in terms of casts, that might be not valid in some cases. It should say that casts in the expansion do not represent normal C# cast operator but just represent conversions that are permitted in 'as' operators. I'll take a note to fix it. Thanks!

关于c# - 当右侧操作数是泛型时, "as"运算符如何翻译?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28151325/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com