2010-11-25 3 views
13

Почему ниже не компилируется? Что особенного в интерфейсе, который заставляет компилятор думать, что он не может отличить от Container<T> до T, когда T - это интерфейс? Я не думаю, что это ковариантная проблема, поскольку я не удручаю, но, возможно, это так. Это совсем как Why C# compiler doesn't call implicit cast operator?, но я не думаю, что это совсем то же самое.C# общий неявный листинг на интерфейсе не удалось

Product pIn =null; 
Product pOut; 
Container<Product> pContainer; 

List<Product> pListIn = null; 
List<Product> pListOut; 
Container<List<Product>> pListContainer; 

IList<Product> pIListIn = null; 
IList<Product> pIListOut; 
Container<IList<Product>> pIListContainer; 

pContainer = pIn; 
pOut = pContainer; // all good 

pListContainer = pListIn; 
pListOut = pListContainer; // all good too 

pIListContainer = pIListIn; // fails , cant do implicit cast for some reason 
pIListOut = pIListContainer; // and here too 

class Container<T> 
{ 
private T value; 

private Container(T item) { value = item; } 

public static implicit operator Container<T>(T item) 
{ 
    return new Container<T>(item); 
} 

public static implicit operator T(Container<T> container) 
{ 
    return container.value; 
} 
} 

Cannot implicitly convert type 'Container<IList<Product>>' to 'IList<Product>'. An explicit conversion exists (are you missing a cast?) 
Cannot implicitly convert type 'IList<Product>' to 'Container<IList<Product>>'. An explicit conversion exists (are you missing a cast?) 
+2

+1 - Интересно, на самом деле. Любопытно, чтобы увидеть ответ. – Lucero 2010-11-25 20:23:25

+1

+1 - Просто эта ошибка компиляции и вы хотите задать вопрос! – TDaver 2011-02-21 16:21:40

ответ

13

преобразования, определяемые пользователем не допускаются на интерфейсах вообще. Это потенциально было бы неоднозначным, потому что тип, который вы пытаетесь преобразовать из, мог реализовать сам интерфейс - на каком этапе было бы означать акцент? Референсное преобразование, подобное нормальному литию, или вызов пользовательского преобразования?

Из раздела 10.3.3 части С # 4 спецификации:

для данного типа источника S и целевого типа T, если S или Т является обнуляемым типом, пусть S0, T0 см, лежащими в основе их типов, иначе S0 и T0 равны S и T соответственно. Класс или структура разрешено объявлять преобразование из типа источника S в целевой тип T только в случае, если все из них являются истинными:

  • S0 и T0 - разные типы.
  • Либо S0, либо T0 - тип класса или структуры, в котором имеет место объявление оператора.
  • Ни S0, ни T0 не являются интерфейсом.
  • За исключением определенных пользователем преобразований, преобразование не существует от S до T или T к S.

и затем позже:

Тем не менее, можно объявить операторов на типичных типах, которые для конкретных аргументов типа указывают преобразования, которые уже существуют в виде предопределенных преобразований
...
В случаях, когда предопределенное преобразование существует между двумя типами, любые пользовательские преобразования между t типы шлангов игнорируются. В частности:

  • Если предопределенный неявное преобразование (§6.1) существует с типа S к типу T, все определенные пользователем преобразования (неявные или явные) из S в T игнорируются.
  • Если предопределенное явное преобразование (§6.2) существует от типа S к типу T, любые пользовательские явные преобразования из S в T игнорируются. Кроме того:
    • Если T - тип интерфейса, пользовательские неявные преобразования из S в T игнорируются.
    • В противном случае пользовательские неявные преобразования из S в T по-прежнему рассматриваются.

Примечание первую вложенную пулю здесь.

(я могу тщательно рекомендую добыть спецификации, кстати. Он доступен в Интернете в various versions and formats, но hardcopy annotated edition также кладезь маленьких самородков из команды и других. Я должен признаться, определенный уклон здесь, поскольку я один из аннотаторов, но игнорируя мои вещи, все остальные примечания заслуживают внимания!)

Смежные вопросы