【问题标题】:C# .NET passing a collection of InterfaceImplementingClass objects to a routine that takes a collection of Interface objectsC# .NET 将 InterfaceImplementingClass 对象的集合传递给采用 Interface 对象集合的例程
【发布时间】:2010-10-09 17:13:55
【问题描述】:

我有一个例程

public void SomeRoutine(List<IFormattable> list) { ... }

然后我尝试调用这个例程

List<Guid>list = new List<Guid>();
list.Add(Guid.NewGuid());
SomeRoutine(list);

它会因编译时错误而失败。 System.Guid 实现 IFormattable,但我得到的错误是

无法从 'System.Collections.Generic.List' 到 'System.Collections.Generic.List'

注意:如果您只使用一组 Guid,您将得到同样的错误。泛型不是原因....

但是!鉴于此

public void SomeRoutine2(IFormattable obj) { ... }

还有这个

Guid a = Guid.NewGuid();
SomeRoutine2(a);

它编译!所以问题是为什么?为什么我能够将 Guid 对象(实现 IFormattable)传递到接受 IFormattable 对象的例程中,但是当我尝试将其扩展为集合(通用列表、数组或其他任何东西)时,我得到转换错误?

我花了很长时间寻找答案,我认为这将是最好的去处。

【问题讨论】:

  • 您确实意识到标记的答案(.NET 4.0 协方差)实际上并不适用于列表,因为泛型现在可以工作?
  • 除非它不适用于带有查找 IFormattable 数组的例程的 Guid 数组......?

标签: c# .net generics interface clr


【解决方案1】:

【讨论】:

  • C# 4.0 协方差不适用于具体类(仅适用于接口),也不适用于列表(仅 IEnumerable - 或纯“输出”的东西)
  • 你说的“纯粹”是什么意思?
  • 我的意思是,IEnumerable&lt;T&gt;IEnumerator&lt;T&gt; 只有“out”用法——即“T Current {get;}”。它将事物标记为“输入”或“输出”,从而实现协方差;但它只适用于一个另一个。您不能使用“in”和“out”(需要哪些列表)。
  • 更正第一个注释;接口 + 委托;但是泛型在这里仍然是一个更好的答案;重新列出和“in”+“out”; Add(T) 将是“in”,枚举器将是“out”,并且索引器是两者;因此列表不适用于 c# 4.0 协方差。
  • 好吧,这确实是有道理的。谢谢:)
【解决方案2】:

您是否尝试过将list 声明为List&lt;IFormattable&gt; 对象而不是List&lt;Guid&gt;?这应该可以帮助您克服编译错误。

【讨论】:

    【解决方案3】:

    问题在于 List 不仅是一个可以从中读取一些 IFormattables 的集合,它还是一个可以添加 IFormattables 的集合。 List 满足第一个要求,但不满足第二个要求。如果 SomeRoutine 是

    public void SomeRoutine(List<IFormattable> list)
    {
        list.Add(5);
    }
    

    Int32 是一个 IFormattable,因此该方法应该能够将它添加到它要求的 List 中。如果编译器允许您传入 List,那将无法正常工作。

    BFree 引用的新 C# 4.0 功能将让您告诉编译器这些东西何时是安全的。你也可以说

    • 虽然我要求提供 IFormattable 参考,但我只会阅读它。如果它确实是一个 Guid 引用,那么我可以安全地将其视为 IFormattable,并且我不会尝试为其分配 Int32。
    • 虽然我要求提供 IFormattable 参考,但我只会写信给它。如果它真的是一个对象引用,那么我可以安全地将我的 IFormattable 分配给它,并且当前值是否不是 IFormattable 也没关系,因为我不会读取它。

    【讨论】:

    • C# 4.0 协方差不适用于具体类(仅适用于接口),也不适用于列表(仅 IEnumerable - 或纯“out”的东西
    • 修正;接口 + 委托;但泛型在这里仍然是一个更好的答案......
    • 好点。当然 List 不能做出 C# 4.0 将允许的“输入”或“输出”断言,因为您仍然需要能够插入和检索 T,所以您也好不到哪里去。 +1 为您的泛型答案。
    【解决方案4】:

    这是一个经典的泛型用例;试试:

    public static void SomeRoutine<T>(IList<T> list) where T : IFormattable
    { ... }
    

    现在在SomeRoutine 中,您可以访问所有IFormattable 成员,但它适用于:

    List<Guid>list; ...
    SomeRoutine(list); // note no need to specify T
    

    编辑:我还 blogged 讨论了这种情况下 4.0 协方差和泛型之间的差异。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-01-25
      • 2014-11-04
      • 2012-11-14
      • 2012-08-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多