C#.NET将一组InterfaceImplementingClass对象传递给一个采用Interface对象集合的例程

时间:2009-02-25 00:40:31

标签: c# .net generics interface clr

我有例行公事

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'

注意:如果您只使用Guids数组,则会出现相同的错误。泛型不是原因......

但是!鉴于此

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

和这个

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

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

我有一段时间找到答案,我认为这将是最好的去处。

4 个答案:

答案 0 :(得分:8)

答案 1 :(得分:5)

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

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协方差和泛型之间的差异。

答案 2 :(得分:3)

问题在于List&lt; IFormattable&gt;不仅是一个集合,您可以从中读取一些IFormattables,它也是一个可以添加IFormattables的集合。列表&lt; Guid&gt;符合第一个要求,但不是第二个要求。如果SomeRoutine

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

Int32是一个IFormattable,因此该方法应该能够将它添加到List&lt; IFormattable&gt;它要求的。如果编译器允许您传入List&lt; Guid&gt;。

,那么这不会起作用

BFree引用的新C#4.0功能将让您在这些事情安全时告诉编译器。你可以说

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

答案 3 :(得分:2)

您是否尝试将list声明为List<IFormattable>个对象而不是List<Guid>?这应该让你超过编译错误。