Почему ограничения типов не являются частью сигнатуры метода?

Поэтому я прочитал "Ограничения не являются частью подписи" Эрика Липперта, и теперь я понимаю, что в спецификации указано, что ограничения типов проверяются ПОСЛЕ разрешения перегрузки, но я до сих пор не понимаю, почему это ДОЛЖНО иметь место. Ниже приведен пример Эрика:

static void Foo<T>(T t) where T : Reptile { }
static void Foo(Animal animal) { }
static void Main() 
{ 
    Foo(new Giraffe()); 
}

Это не компилируется, потому что разрешение перегрузки для: Foo(new Giraffe()) делает вывод, что Foo<Giraffe> является лучшим соответствием перегрузки, но тогда ограничения типа не выполняются, и выдается ошибка времени компиляции. По словам Эрика:

Принцип здесь - разрешение перегрузки (и вывод типа метода), чтобы найти наилучшее возможное соответствие между списком аргументов и списком формальных параметров каждого метода-кандидата. То есть они смотрят на сигнатуру метода-кандидата.

Типовые ограничения НЕ являются частью подписи, но почему они не могут быть? В каких сценариях плохая идея рассматривать ограничения типов как часть сигнатуры? Это просто сложно или невозможно реализовать? Я не сторонник того, что, если по какой-либо причине невозможно выбрать наилучшую перегрузку, молча отступайте ко второму. Я бы ненавидел это. Я просто пытаюсь понять, почему ограничения типа не могут быть использованы, чтобы повлиять на выбор наилучшей перегрузки.

Я представляю себе, что внутри компилятора C# только для разрешения перегрузки (метод не переписывает метод):

static void Foo<T>(T t) where T : Reptile { }

преобразуется в:

static void Foo(Reptile  t) { }

Почему вы не можете "вставить" ограничения типа в формальный список параметров? Как это меняет подпись каким-либо образом? Я чувствую, что это только усиливает подпись. затем Foo<Reptile> никогда не будет рассматриваться в качестве кандидата на перегрузку.

Редактировать 2: Не удивительно, что мой вопрос был настолько запутанным. Я не читал должным образом блог Эрика и привел неправильный пример. Я отредактировал в примере, который я считаю более подходящим. Я также изменил название, чтобы быть более конкретным. Этот вопрос не кажется таким простым, как я себе представлял, возможно, мне не хватает какой-то важной концепции. Я менее уверен, что это материал stackru, возможно, лучше будет перенести этот вопрос / обсуждение в другое место.

2 ответа

Решение

Компилятор C# не должен рассматривать ограничения типа как часть сигнатуры метода, поскольку они не являются частью сигнатуры метода для CLR. Было бы катастрофично, если бы разрешение перегрузки работало по-разному для разных языков (главным образом из-за динамического связывания, которое может происходить во время выполнения и не должно отличаться от одного языка к другому, иначе бы все ады могли развалиться).

Почему было решено, что эти ограничения не будут являться частью сигнатуры метода для CLR, - это вообще другой вопрос, и я мог только делать плохо обоснованные предположения об этом. Я позволю знающим людям ответить на этот вопрос.

Если T соответствует нескольким ограничениям, вы создаете неоднозначность, которая не может быть автоматически разрешена. Например, у вас есть один общий класс с ограничением

where T : IFirst

и другой с ограничением

where T : ISecond

Теперь вы хотите, чтобы T был классом, который реализует оба IFirst а также ISecond,

Пример конкретного кода:

public interface IFirst
{
    void F();
}

public interface ISecond
{
    void S();
}

// Should the compiler pick this "overload"?
public class My<T> where T : IFirst
{
}

// Or this one?
public class My<T> where T : ISecond
{
}

public class Foo : IFirst, ISecond
{
    public void Bar()
    {
        My<Foo> myFoo = new My<Foo>();
    }

    public void F() { }
    public void S() { }
}
Другие вопросы по тегам