Ошибка компилятора C #? Почему это неявное пользовательское преобразование не компилируется?
Учитывая следующую структуру:
public struct Foo { public Foo(T obj) { } public static implicit operator Foo(T input) { return new Foo(input); } }
Этот код компилирует:
private Foo MakeFoo() { string c = "hello"; return c; // Success: string is ICloneable, ICloneable implicitly converted to Foo }
Но этот код не компилируется – почему?
- Каков размер пустой структуры в C?
- Утверждение времени компиляции?
- Какова цель (-ы) встроенного?
- На лету, компиляция Java-кода в памяти для Java 5 и Java 6
- Обновление GCC на OSX
private Foo MakeFoo() { ICloneable c = "hello"; return c; // Error: ICloneable can't be converted to Foo. WTH? }
- Монокомпилятор как услуга (MCS)
- неявный оператор с использованием интерфейсов
- Зачем компилировать ошибку «Использование неназначенной локальной переменной»?
- Значение типа компилятора Разрешение и жестко заданные значения «0» Целочисленные значения
- Как компилятор C # обнаруживает типы COM?
- Как создать АСТ с ANTLR4?
- Почему компилятор C # испускает инструкцию callvirt для вызова метода GetType ()?
- Что определяет размер целого числа?
По-видимому, неявные пользовательские преобразования не работают, когда один из типов является интерфейсом. Из спецификаций C #:
6.4.1 Разрешенные пользовательские преобразования
C # разрешает объявлять только определенные пользовательские преобразования. В частности, невозможно переопределить уже существующее неявное или явное преобразование. Для данного типа источника S и целевого типа T, если S или T являются типами NULL, пусть S0 и T0 относятся к их базовым типам, в противном случае S0 и T0 равны S и T соответственно. Класс или структура разрешено объявлять преобразование из типа источника S в целевой тип T только в том случае, если все следующие значения истинны:
- S0 и T0 – разные типы.
- Либо S0, либо T0 – тип classа или структуры, в котором имеет место объявление оператора.
- Ни S0, ни T0 не являются интерфейсом .
- Исключая пользовательские преобразования, преобразование не существует от S до T или от T до S.
В первом методе оба типа не являются типами интерфейсов, поэтому пользовательское неявное преобразование работает.
Спецификации не очень ясны, но мне кажется, что если один из типов связан с типом интерфейса, то компилятор даже не пытается найти какие-либо пользовательские неявные преобразования.
(Следуя за комментариями принятого ответа.)
Да, это очень, очень запутанная часть спецификации. Весь бит о «охватывающих типы» в частности глубоко испорчен. Я уже несколько лет пытаюсь найти время, чтобы полностью переписать весь этот раздел во что-то более последовательное, но он никогда не был достаточно высоким приоритетом.
По сути, у нас есть противоречие; мы говорим, что нет никаких пользовательских неявных преобразований, включающих интерфейсы, но ясно, что это не так в данном случае; существует определенное пользователем неявное преобразование из IC в Foo
, продемонстрированное тем фактом, что строка переходит к Foo
через это преобразование.
То, что мы действительно должны лучше подчеркивать, – это строка, которую вы цитировали:
В частности, невозможно переопределить уже существующее неявное или явное преобразование.
Вот что мотивирует все это; желание не позволить вам когда-либо думать, что вы выполняете тест типа, сохраняющий представление, когда на самом деле вы вызываете пользовательский метод. Рассмотрим, например, этот вариант:
interface IBar {} interface IFoo : IBar {} class Foo : IFoo { public static explicit operator Foo (T input) { whatever } } class Blah : Foo {} ... IBar bar = new Blah(); Foo foo = (Foo )bar;
Теперь, вызывает ли это пользовательское явное преобразование или нет? Объект действительно получен из Foo, поэтому вы надеетесь, что этого не произойдет; это должен быть простой тест типа и ссылочное задание, а не вызов вспомогательного метода. Приведение значения интерфейса всегда рассматривается как тест типа, поскольку почти всегда возможно, что объект действительно имеет этот тип и действительно реализует этот интерфейс. Мы не хотим отказывать вам в возможности сделать дешевое преобразование, сохраняющее представление.