将嵌套集合转换为接口

时间:2014-04-23 11:47:15

标签: c#

为什么呢?当然,我不需要用户定义的转化,因为List(T)IList(T)HashSet(T)IEnumerable(T)。感谢。

  

无法隐式转换类型&#39; System.Collections.Generic.List<System.Collections.Generic.HashSet<string>>&#39;到&#39; System.Collections.Generic.IList<System.Collections.Generic.IEnumerable<string>>&#39;。存在显式转换(您是否错过了演员?)

class Program {

    static IList<IEnumerable<string>> GetSet() {
        return new List<HashSet<string>>();
    }

}

2 个答案:

答案 0 :(得分:2)

我认为我真正需要的是方差的简单解释 - 逆变和协方差 - 在C#泛型的背景下我找到了herehere

错误信息并没有真正引导我,但现在我将总结一下:

<强>逆变

泛型类,当然是类的模板而不是类定义,可以使用 关键字使逆变成为逆变。逆变类允许从基类实例到派生类实例的赋值,即BorderCollie = Dog

public interface AllowAssignmentsFromBaseToDerived<in T>

<强>协方差

可以使用 out 关键字将通用类设为协变。协变类允许从派生类实例到基类实例的赋值,即Dog = BorderCollie

public interface AllowAssignmentsFromDerivedToBase<out T>

自C#1.0以来的数组类型和自C#2.0以来的委托类型以及自C#4.0以来的泛型类型参数都支持方差。

很高兴有更多的回应来覆盖我错过的更多积分,仍然感觉有点不明智。

here取消更多信息:

  

如何创建变体通用接口并自行委派?

     

out关键字将类型参数标记为covariant,而in   关键字将其标记为逆变。两条最重要的规则   记住:

     
      
  1. 如果仅使用泛型类型参数,则可将其标记为协变   作为方法返回类型,并不用作一种形式方法   参数。

  2.   
  3. 反之亦然,如果是类型,您可以将类型标记为逆变   仅用作一种形式的方法参数而不用作   方法返回类型。

  4.   
    interface IVariant<out R, in A>
    {
        // These methods satisfy the rules.
        R GetR();
        void SetA(A sampleArg);
        R GetRSetA(A sampleArg);

        // And these don’t.
        // A GetA();
        // void SetR(R sampleArg);
        // A GetASetR(R sampleArg);
    }

此外,如果扩展变体通用接口,则默认情况下它是不变的。您需要根据需要指定In或Out。

最后,由于我的解释将严重不足,请尝试Eric Lippert's blog

答案 1 :(得分:1)

因为IList<T>是不变的。

为了说明这是一个问题,请考虑以下示例:

  

IList<T>提供了Add(T object)IEnumerable<string>的方法,这会与您的构造函数表达式new List<HashSet<string>>()冲突。这意味着我可以调用您的program.GetSet()并添加new ArrayList<string>(),但您构建的实例将不允许它,因为它的合同只包含HashSet<string>个实例(你会是什么)当人们询问包含GetSet()的{​​{1}}的内容时返回

类型参数是双重嵌套的事实并不重要。例如,ArrayList<T>也不是IList<Object>的超类。


IList<FooClass>本身不是这种情况(意味着IEnumerable<T>也是IEnumerable<T>),因为IEnumerable<SuperT>的唯一功能是输出值。由于Liskov替代原则,这是允许的。

  

原则说,当走在一个阶级层次结构中时,   返回类型只能变得更通用(超类/接口)   并且参数类型只能变得更具体(sub   类/接口)。


C#提供了使用泛型类型声明中的IEnumerable<T>in关键字来处理此原则(称为方差)的工具。

例如,如果您确定out也是Foo<SubT>,则可以将其定义为:

Foo<T>

在这种情况下,public class Foo<out T> { T getResult () { //do something } } T有协变关系。如果类型参数仅用作输入,则可以进一步指定。例如,Foo显然是以下定义中Bar<T>的特例:

Bar<SubT>