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

StackOverflow https://stackoverflow.com/questions/9440888

Вопрос

ОБНОВЛЯТЬ: Начиная с C# 7.3, это больше не должно быть проблемой.Из примечаний к выпуску:

Если группа методов содержит некоторые универсальные методы, аргументы типа которых не удовлетворяют их ограничениям, эти члены удаляются из набора кандидатов.

До С# 7.3:

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

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: Неудивительно, что мой вопрос оказался таким запутанным.Я неправильно прочитал блог Эрика и привел неверный пример.Я отредактировал пример, который считаю более подходящим.Я также изменил название, чтобы оно было более конкретным.Этот вопрос кажется не таким простым, как я сначала себе представлял, возможно, я упускаю какую-то важную концепцию.Я менее уверен, что это материал stackoverflow, возможно, лучше перенести этот вопрос/обсуждение в другое место.

Это было полезно?

Решение

Компилятор 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() { }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top