为什么以下不能编译?当Container<T>
是接口时,导致编译器认为无法从T
转换为T
的接口有什么特别之处?我不认为这是一个协变问题,因为我不是在倾斜,但也许是。这很像Why C# compiler doesn't call implicit cast operator?,但我认为它并不完全相同。
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?)
答案 0 :(得分:18)
接口上根本不允许用户定义的转换。它可能是模棱两可的,因为你试图转换的类型可以实现接口本身 - 此时演员的意思是什么?引用转换,如普通转换,或调用用户定义的转换?
来自C#4规范的第10.3.3节:
对于给定的源类型S和目标类型T,如果S或T是可空类型,则让S0和T0引用它们的基础类型,否则S0和T0分别等于S和T.只有满足以下所有条件时,才允许类或结构声明从源类型S到目标类型T的转换:
- S0和T0是不同的类型。
- S0或T0是发生运算符声明的类或结构类型。
- S0和T0都不是接口类型。
- 不包括用户定义的转化,从S到T或从T到S不存在转换。
然后再说:
但是,可以在泛型类型上声明运算符,对于特定类型参数,指定已作为预定义转换存在的转换
...
如果两种类型之间存在预定义的转换,则忽略这些类型之间的任何用户定义的转换。具体做法是:
- 如果从类型S到类型T存在预定义的隐式转换(第6.1节),则忽略从S到T的所有用户定义的转换(隐式或显式)。
- 如果从类型S到类型T存在预定义的显式转换(第6.2节),则忽略从S到T的任何用户定义的显式转换。此外:
- 如果T是接口类型,则忽略用户定义的从S到T的隐式转换。
- 否则,仍会考虑用户定义的从S到T的隐式转换。
请注意这里的第一个嵌套项目符号。
(我可以彻底建议顺便掌握规格。它可以在various versions and formats在线获取,但是hardcopy annotated edition也是来自的小金块团队和其他人。我应该在这里承认一定的偏见,因为我是其中一个注释者 - 但忽略了我的东西,所有其他注释都值得一读!)