Почему ограничения типов не являются частью сигнатуры метода?
Поэтому я прочитал "Ограничения не являются частью подписи" Эрика Липперта, и теперь я понимаю, что в спецификации указано, что ограничения типов проверяются ПОСЛЕ разрешения перегрузки, но я до сих пор не понимаю, почему это ДОЛЖНО иметь место. Ниже приведен пример Эрика:
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() { }
}