C#通用隐式转换接口失败

C#通用隐式转换接口失败,c#,generics,c#-4.0,casting,C#,Generics,C# 4.0,Casting,为什么下面的代码不能编译?当t是一个接口时,接口有什么特殊之处使编译器认为它不能从容器转换到t?我不认为这是一个协变的问题,因为我没有悲观,但也许是这样。这很像,但我觉得不太一样 Product pIn =null; Product pOut; Container<Product> pContainer; List<Product> pListIn = null; List<Product> pListOut; Container<List<Pr

为什么下面的代码不能编译?当
t
是一个接口时,接口有什么特殊之处使编译器认为它不能从
容器
转换到
t
?我不认为这是一个协变的问题,因为我没有悲观,但也许是这样。这很像,但我觉得不太一样

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
产品pIn=null;
产品撅嘴;
集装箱集装箱;
列表pListIn=null;
列表plistotut;
集装箱夹板集装箱;
IList pIListIn=null;
IList pIListOut;
集装箱垛式集装箱;
pContainer=pIn;
pOut=pContainer;//一切都好
pListContainer=pListIn;
pListOut=pListContainer;//也很好
pIListContainer=pIListIn;//失败,由于某些原因无法执行隐式强制转换
pIListOut=pIListContainer;//这里也是

类容器
{
私人T值;
私有容器(T项){value=item;}
公共静态隐式运算符容器(T项)
{
退回新集装箱(项目);
}
公共静态隐式运算符T(容器)
{
返回容器值;
}
}

无法将类型“Container”隐式转换为“IList”。存在显式转换(是否缺少强制转换?)
无法将类型“IList”隐式转换为“Container”。存在显式转换(是否缺少强制转换?)

接口上根本不允许用户定义的转换。这可能是不明确的,因为您试图从中转换的类型可以实现接口本身——此时强制转换意味着什么?像普通转换一样的引用转换,还是用户定义转换的调用

根据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的隐式转换
注意这里的第一个嵌套项目符号


(顺便说一句,我完全可以推荐你掌握这个规范。它在网上可以找到,但它也是团队和其他人的一个小金块的金矿。我应该在这里承认一定的偏见,因为我是注释者之一-但是忽略我的东西,所有其他注释都很值得一读!)

用户定义的转换根本不允许在接口上进行。这可能是不明确的,因为您试图从中转换的类型可以实现接口本身——此时强制转换意味着什么?像普通转换一样的引用转换,还是用户定义转换的调用

根据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的隐式转换
注意这里的第一个嵌套项目符号


(顺便说一句,我完全可以推荐你掌握这个规范。它可以在网上找到,但它也是团队和其他人的一个小金块的金矿。我应该在这里承认一定的偏见,因为我是注释者之一-但是忽略我的东西,所有其他注释都很值得一读!)

+1-事实上很有趣。好奇地想看看答案。+1-刚刚发现这个编译错误,想问这个+1-对……感兴趣
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?)