【问题标题】:double covariance双协方差
【发布时间】:2011-07-22 23:18:40
【问题描述】:

我有

public interface IFoo
{
   IEnumerable<IThingy> Thingies{get;}
}

我希望以后能够做到

class Thing1 : IThingy
{
   ...
}
class ImplementFoo : IFoo
{
   List<Thing1> m_things;
   IEnumerable<IThingy> Thingies {get {return m_things;}}
}

ImplementFoo.Thingies 返回 Thing1(即 IThings)的 IList(即 IEnumerable)。所以理论上这段代码应该可以工作,但事实并非如此。 VS 建议在 getter 中进行强制转换;编译但在运行时失败。我对 c# 4 的协方差期望过高吗?

VS 2010 -> Silverlight 4. 这是编译错误

无法将类型“System.Collections.Generic.List&lt;MyProj.Column&gt;”隐式转换为“System.Collections.Generic.IEnumerable&lt;MyProj.IColumn&gt;”。存在显式转换(您是否缺少演员表?)

编辑:人们告诉我这应该可以,但在 SL4 中不起作用

【问题讨论】:

  • 您的项目是否面向 .NET 4?
  • .net 4 是肯定的。让我再试一次。实际上是 Silverlight 4

标签: c# covariance


【解决方案1】:

这在 C#/.NET 4 中运行良好。这是一个完整的、编译和工作的示例:

namespace Test
{
    using System;
    using System.Collections.Generic;
    using System.Linq;

    public interface IThingy { }

    public interface IFoo
    {
        IEnumerable<IThingy> Thingies { get; }
    }

    internal class Thing1 : IThingy { }

    internal class ImplementFoo : IFoo
    {
        private List<Thing1> m_things = new List<Thing1>() { new Thing1() };

        public IEnumerable<IThingy> Thingies
        {
            get { return m_things; }
        }
    }

    internal class Program
    {
        private static void Main(string[] args)
        {
            var impl = new ImplementFoo();

            Console.WriteLine(impl.Thingies.Count());


            Console.WriteLine("Press any key to exit");
            Console.ReadKey();
        }
    }
}

我怀疑问题在于您的目标是 .NET 3.5sp1 或更早版本,而不是 .NET 4.0。协方差仅在面向 .NET 4 时才能正常工作,因为它需要更改新的框架。在这种情况下,IEnumerable&lt;T&gt; 在 .NET 4 中实际上是 IEnumerable&lt;out T&gt;,这是它工作所必需的。

【讨论】:

  • 这解释了为什么它对我不起作用,我正在使用 ICollection&lt;&gt;Collection&lt;&gt; 进行测试。似乎 ICollection 不是 out T
  • @Anthony: ICollection&lt;T&gt; 具有将 T 作为输入的方法。如果你有一个香蕉的集合,你可以把它当作一个水果的集合,那么你可以把一个橙子放到一个香蕉的集合中。这不应该是合法的,所以集合接口在 T 中是不允许协变的。
  • @Anthony Sottile 是的,没错。 ICollection 不是在 4.0 中实现协变/逆变的接口之一。
  • @Eric 现在很有意义。我想我应该考虑一下成为可编辑集合的含义,现在我的评论听起来很愚蠢:P
  • @Anthony:不用担心;这些东西很难让你的大脑动起来!
【解决方案2】:

您可以使用Cast extension method:

class ImplementFoo : IFoo
{
    List<Thing1> m_things;

    IEnumerable<IThingy> Thingies 
    {
        get
        {
            return m_things.Cast<IThingy>();
        }
    }
}

这是因为IEnumerable&lt;Thing1&gt; 没有隐式实现IEnumerable&lt;IThingy&gt;

【讨论】:

【解决方案3】:

这是 SL4 和 CLR4 之间的区别。 IEnumerable 接口未标记为“out”。显然已在 SL5 中修复

【讨论】:

    猜你喜欢
    • 2016-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-06
    • 1970-01-01
    相关资源
    最近更新 更多