(отслеживание комментариев принятого ответа.)
Да, это очень, очень запутанная часть спецификации. Все о «охватывающих типах», в частности, глубоко ошибочно. Уже несколько лет я пытаюсь найти время, чтобы полностью переписать весь этот раздел в нечто более связное, но это никогда не было достаточно высоким приоритетом.
По сути, то, что мы имеем здесь, является противоречием; мы говорим , что не существует пользовательских неявных преобразований с участием интерфейсов, но ясно, что в этом случае это не так; есть пользовательское неявное преобразование из IC в Foo<IC>
, что подтверждается тем фактом, что в результате этого преобразования строка переходит в Foo<IC>
.
То, что мы действительно должны подчеркнуть лучше, это строка, которую вы цитировали:
В частности, невозможно
переопределить уже существующее неявное
или явное преобразование.
Вот что мотивирует все это; желание не позволить вам когда-либо думать, что вы выполняете тестирование типа с сохранением представления, когда на самом деле вы вызываете определенный пользователем метод. Рассмотрим, например, этот вариант:
interface IBar {}
interface IFoo : IBar {}
class Foo<T> : IFoo
{
public static explicit operator Foo<T>(T input) { whatever }
}
class Blah : Foo<IBar> {}
...
IBar bar = new Blah();
Foo<IBar> foo = (Foo<IBar>)bar;
Теперь, вызывает ли это заданное пользователем явное преобразование или нет? Объект действительно является производным от Foo, так что вы надеетесь, что это не так; это должен быть простой тест типа и присвоение ссылки, а не вызов вспомогательного метода. Приведение значения интерфейса всегда рассматривается как проверка типа, потому что почти всегда возможно, что объект действительно принадлежит к этому типу и действительно реализует этот интерфейс. Мы не хотим отказывать вам в возможности делать дешевое преобразование, сохраняющее представление.