【问题标题】:Implicit Reference Conversion from reference type to interface for user defined types从引用类型到用户定义类型的接口的隐式引用转换
【发布时间】:2013-02-08 22:03:37
【问题描述】:

来自 C# 4.0 规范第 6.1.6 节:

隐式引用转换为:

[...]

从任何引用类型到接口或委托类型 T,如果它有 到接口的隐式标识或引用转换或 委托类型 T0 和 T0 可通过变量 (13.1.3.2) 转换为 T。

Vladimir Reshetnikov 告诉我们,存在从 List<string>IEnumerable<object> 的隐式引用转换。但是,我如何将其应用于用户定义的类型(甚至可能)?

我尝试了隐式运算符、自定义派生类型和其中的一些变体......但我无法重现场景。我有:

class Program
{
    static void Main(string[] args)
    {
        IEnumerable<object> specialClassConversion = new List<string>();
        IEnumerable<A> userdefinedTypeConversion = new List<B>();
        A implicitConversion = new B();//varience-convertible
        IC<A> explicitConversion = (IC<A>)new D<B>();//OK, varience-convertible
        IC<A> implicitConversion2 = new D<B>();//does not compile
    }
}

class A { }

class B : A { }

interface IC<T> { }    

class D<T> 
{
    //public static implicit operator IC(D<T> m)//Error: user-defined conversions to or from an interface are not allowed
    //{
    //    return null;
    //}
}

【问题讨论】:

  • 你引用的摘录中的“隐式转换”并不意味着“存在隐式转换运算符”,它只是意味着“不需要显式转换的转换”
  • IC&lt;A&gt; explicitConversion = (IC&lt;A&gt;)new D&lt;B&gt;(); 也不行,演员应该在运行时失败。除非接口被声明为interface IC&lt;in T&gt;interface&lt;out T&gt;。 (我不记得究竟哪个是泛型实例之间的子类型关系以及这对子类型关系意味着什么。)如果它们可变可转换的,那么后面的行将编译。
  • @millimoose 其实"an implicit conversion operator exists" 正是的意思。请注意,语言提供从类型到其所有基类型以及它实现的任何接口的隐式转换,因此它不仅仅是用户或语言定义的转换运算符。
  • @Servy Under operator 我的意思是 C# 允许你实现的特殊方法——我不认为语言提供的转换是“运算符”。我想我应该更好地表达该评论。更好的版本应该是:“隐式转换”并不only 意味着您已经定义了一个隐式转换运算符方法,而是 any 不需要的转换显式转换(用户定义或语言定义。)
  • 嗯,List&lt;T&gt;IEnumerable&lt;T&gt; 都是用户定义的类型,所以它一定是有可能的。

标签: c#


【解决方案1】:

如果您希望用户定义的类或结构可以隐式转换为接口,请让您的类/结构实现该接口。

(编辑)

如果您希望IC&lt;B&gt; 可以隐式转换为IC&lt;A&gt;,请通过指定out 关键字interface IC&lt;out T&gt; { }T 中创建IC&lt;T&gt; 接口协变。您给出的规范中的引用表明这两个隐式转换的“组合”也是隐式转换。

来源:

interface IC<out T> {  }

class D<T> : IC<T>  { }

(结束编辑)

关于List&lt;string&gt; 类,它实现了IEnumerable&lt;string&gt;,而IEnumerable&lt;string&gt; 又可以(隐式)转换为IEnumerable&lt;object&gt;,因为IEnumerable&lt;out T&gt;T 中的协变out)。

(他们不允许您创建与接口转换/从接口转换的public static implicit operator 的一个原因是,somone 可以编写一个从您的类继承的派生类并且实现了接口。这将在他们的类和接口之间进行“自然”转换,但public static implicit operator 也将适用,导致两次转换(一个“自然”和一个“用户定义”)类型之间,这会令人困惑和模棱两可。)

【讨论】:

  • 你能演示一下它是如何与 OP 中的代码一起工作的吗?我尝试实现该接口并遇到了各种其他实现问题...在 OP 的 cmets 中记录了一个问题。
  • @P.Brian.Mackey 如果你想让你的接口像IEnumerable&lt;&gt;一样协变,写interface IC&lt;out T&gt; { }(注意out)。一定要让D 实现接口:class D&lt;T&gt; : IC&lt;T&gt; { } 规范中引用的“variance-convertible”东西是关于协变和逆变的,在您的代码示例中,使用协变。
  • 进行涉及接口类型的转换的唯一方法是在类C&lt;T&gt;中进行从C&lt;T&gt;T的转换,然后构造C&lt;IFoo&gt;。在编译器中处理这种情况的代码让我投票选出编译器中最神秘和最难的代码,而且规范很难阅读。让 Roslyn 匹配规范和以前的编译器的一些相似之处是 Roslyn 语义分析工作中最艰巨的挑战之一。
  • @EricLippert 我用 Visual C# 5.0 编译器试了一下。在这种情况下,似乎从不考虑转换为IFoo。在右侧的“相关”列中,我发现了这个问题:C# compiler bug? Why doesn't this implicit user-defined conversion compile?
  • @EricLippert 的帖子帮助我理解了我在这种情况下遗漏的一个微妙的协变问题:blogs.msdn.com/b/ericlippert/archive/2009/11/30/…
猜你喜欢
  • 1970-01-01
  • 2013-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多