C#编译器如何处理重载显式转换运算符?

时间:2016-03-08 12:32:57

标签: c# compiler-construction

编译器应该翻译此代码:

public static explicit operator Int64(MyNumber n)
{
    return n.ToInteger();
}

public static explicit operator Double(MyNumber n)
{
    return n.ToDouble();
}

两个具有相同名称和签名但仅由返回类型不同的方法,例如

public static Int64 ExplicitCast(MyNumber n)
...

public static Double ExplicitCast(MyNumber n)
...

但是,我们不允许使用只有返回类型不同的方法。窗帘背后会发生什么?

2 个答案:

答案 0 :(得分:7)

从技术上讲,CLS(公共语言规范,指定所有.NET语言应支持的.NET虚拟机的子部分的规范)表示显式强制转换方法的名称应为op_Explicit(请参阅例如http://goo.gl/wn8dHq)。

您可以使用多个具有相同名称且只有不同返回类型的方法的限制是C#的限制。 IL语言(即.NET虚拟机的语言)没有此限制。

例如参见:https://stackoverflow.com/a/442100/613130

  

但是,某些语言(例如MSIL)允许按返回类型进行重载。他们当然也面临上述困难,但他们有解决方法,您必须查阅他们的文档。

https://blogs.msdn.microsoft.com/abhinaba/2005/10/07/c-cil-supports-overloading-by-return-type/

  

但是,CIL确实支持按返回类型重载方法,即使C#,VB没有。实现转换运算符重载C#编译器使用此功能(我知道一种用法,我确信还有更多:))

(这就是这里提到的情况)

如果您想查看ECMA-335标准:

  

I.8.11.1方法定义

     

方法签名定义了调用约定,类型   方法的参数和方法的返回类型

如果您有兴趣知道如何调用该方法......那么......很明显,如果IL语言支持返回类型的重载,那么它的call指令必须支持它: - )

例如http://goo.gl/CS4FPb

call int64 MyNumber::op_Explicit(class MyNumber)

VS

call float64 MyNumber::op_Explicit(class MyNumber)

请注意,CLS通常仅根据返回类型禁止重载...但它有op_Implicit(隐式强制转换运算符)和op_Explicit(显式强制转换运算符)的异常(来自同一个) ECMA-335文件):

  

CLS规则38:属性和方法只能根据数量和类型重载   它们的参数,除了名为op_Implicit和op_Explicit的转换运算符之外   也可以根据返回类型重载。

答案 1 :(得分:1)

我不确定你问题的目的,所以这是我能给你的最佳答案。上面的代码编译成这样的

MyNumber.op_Explicit:
IL_0000:  nop         
IL_0001:  ldarg.0     
IL_0002:  callvirt    UserQuery+MyNumber.ToInteger
IL_0007:  stloc.0     
IL_0008:  br.s        IL_000A
IL_000A:  ldloc.0     
IL_000B:  ret         

MyNumber.op_Explicit:
IL_0000:  nop         
IL_0001:  ldarg.0     
IL_0002:  callvirt    UserQuery+MyNumber.ToDouble
IL_0007:  stloc.0     
IL_0008:  br.s        IL_000A
IL_000A:  ldloc.0     
IL_000B:  ret      

它出现的原因"不一致"是因为关键字explicit operator。它告诉编译器生成代码的方式与显式转换中的代码不同。

如果没有它,你会得到这样的东西:

MyNumber.Double2:
IL_0000:  nop         
IL_0001:  ldarg.0     
IL_0002:  callvirt    UserQuery+MyNumber.ToDouble
IL_0007:  stloc.0     
IL_0008:  br.s        IL_000A
IL_000A:  ldloc.0     
IL_000B:  ret