Не удается разрешить метод F #, который был переопределен и перегружен из C # - PullRequest
21 голосов
/ 23 ноября 2011

Следующий код F # объявляет базовый и наследующий классы. Базовый класс имеет виртуальный метод Test с реализацией по умолчанию. Класс-потомок переопределяет метод базового класса, а также добавляет новый перегруженный метод «Test». Этот код прекрасно компилируется и не вызывает проблем при доступе к любому из потомков методов 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

Однако попытка вызвать переопределение потомка «Test» из C # приводит к ошибке компиляции:

var result = td.Test (3); <- Никакая перегрузка для метода 'Test' не принимает 1 аргумент </p>

Полный код 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();
    }
  }
}

Странно то, что intellisense VisualStudio видит две перегруженные функции и предоставляет правильные подписи для обеих. Он не выдает предупреждений или ошибок до того, как сборка завершится неудачей, и только подсвечивает строку после этого.

Я полностью реализовал этот сценарий в C # и не столкнулся с той же проблемой.

У кого-нибудь есть идеи, что здесь происходит?

1 Ответ

17 голосов
/ 23 ноября 2011

Без сомнения, вы знаете, что если вы опустите член Test(x,y) из типа Descendant - или просто переименуете его Test2(x,y) - тогда код C # будет скомпилирован и запущен, как и ожидалось.

Просмотр IL, сгенерированного для вашего исходного типа Descendant, дает подсказку:

.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.

The Спецификация ECMA CLI может сказать о hidebysig следующее.(Раздел 15.4.2.2, выделение жирным шрифтом - мое.)

hidebysig поставляется для использования инструментов и игнорируется VES.Он указывает, что объявленный метод скрывает все методы базовых типов классов, которые имеют совпадающую сигнатуру метода; если не указано, метод должен скрывать все методы с одинаковыми именами, независимо от сигнатуры .

Таким образом, компилятор F # пропускает атрибут hidebysig, что означает, что *Метод 1029 * скрывает все остальные методы с именем Test.Хотя hidebysig предназначен только для «использования инструментов», похоже, что компилятор C # является одним из тех инструментов, которые его используют!

Мне кажется, это может быть ошибка в компиляторе F #,но так как я никогда не смотрел на спецификацию F #, всегда возможно, что это разрешенное / указанное поведение.

...