【问题标题】:Cannot resolve an F# method that has been both overridden and overloaded from C#无法解析已从 C# 覆盖和重载的 F# 方法
【发布时间】:2011-11-23 16:47:09
【问题描述】:

以下 F# 代码声明基类和后代类。基类有一个带有默认实现的虚拟方法“Test”。后代类覆盖基类方法并添加一个新的重载“测试”方法。此代码编译良好,并且在访问任何一个后代“测试”方法时都不会出现问题。

F# 代码:

module OverrideTest
  [<AbstractClass>]
  type Base() =
    abstract member Test : int -> int
    default this.Test x = x + 1

  type Descendant() =
    inherit Base()
    override this.Test x    = x - 1
    member this.Test (x, y) = x - y

但是,尝试从 C# 调用后代对“Test”的覆盖会导致编译错误:

var 结果 = td.Test(3);

完整的 C# 代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Client
{
  class Program
  {
    static void Main(string[] args)
    {
      var td = new OverrideTest.Descendant();
      var result = td.Test(3);
      Console.WriteLine(result);
      Console.ReadKey();
    }
  }
}

奇怪的是,VisualStudio 的智能感知看到了这两个重载函数,并为两者提供了正确的签名。在构建失败之前它不会给出警告或错误,并且只会在之后突出显示该行。

我已经完全用 C# 重新实现了这个场景,并且没有遇到同样的问题。

有人知道这里发生了什么吗?

【问题讨论】:

  • 您是否比较了两种语言发出的 IL?
  • 我在反射器中看到的唯一奇怪的事情是基本方法显示为override,而不是virtual。这似乎是因为基本方法没有newslot 属性。
  • 我认为这是 C# 编译器或 F# 编译器中的一个错误,但我不确定是哪一个(我猜是 C#)。
  • @svick - Base 方法中缺少 newslot 仅意味着如果 its 基类(在本例中为 obj)被更改为具有正确签名的虚拟Test 方法,Base.Test 将覆盖它而不是隐藏它。我认为 F# 最好包含 newslot 以避免版本控制问题,但我不明白为什么在这种情况下会导致任何问题。
  • 这可能是一个错误——我们将对其进行调查。感谢您的报告!唐娜·马拉里 (MSFT)

标签: c# f# interop overloading overriding


【解决方案1】:

毫无疑问,您知道如果您从 Descendant 类型中省略 Test(x,y) 成员 - 或者只是将其重命名为 Test2(x,y) - 那么 C# 代码将按预期编译和运行。

查看为您的原始 Descendant 类型生成的 IL 提供了一个线索:

.method public hidebysig virtual
    instance int32 Test (
        int32 x
    ) cil managed ...

.method public 
    instance int32 Test (
        int32 x,
        int32 y
    ) cil managed ...

注意Test(x,y) 方法上没有hidebysig 属性。

ECMA CLI specification 对hidebysig 有以下看法。 (第 15.4.2.2 节,粗体强调的是我的。)

hidebysig 提供用于工具的使用,并被 VES。它指定声明的方法隐藏所有的方法 具有匹配方法签名的基类类型; 什么时候 省略,该方法应隐藏所有同名方法, 不管签名是什么。

因此,F# 编译器省略了hidebysig 属性,这意味着Test(x,y) 方法隐藏了所有其他名为Test 的方法。虽然hidebysig 只是“供工具使用”,但似乎 C# 编译器就是使用它的工具之一!

在我看来,这可能是 F# 编译器中的一个错误,但由于我从未查看过 F# 规范,因此这始终可能是允许/指定的行为。

【讨论】:

  • +1:必须读几遍才能掌握of the same name。 IMO 句子的最后一部分也应该是BOLD。
  • 那是 得到 是一个错误。对吗?
  • @Daniel:我想不出应该省略hidebysig 的原因。 (我也从来不知道)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多