Почему ограничения типов не являются частью сигнатуры метода? - PullRequest
9 голосов
/ 25 февраля 2012

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

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

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

Ответы [ 2 ]

5 голосов
/ 26 февраля 2012

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

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

0 голосов
/ 25 февраля 2012

Если 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() { }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...