13

如果我想创建一个将 的实例IList作为参数的方法(或任何其他接口,但让我们IList用作示例),我可以创建一个具有类型约束的泛型方法,例如:

public static void Foo1<T>(T list) where T : IList
{

}

或者,我可以创建一个直接采用IList参数的方法:

public static void Foo2(IList list)
{

}

出于所有意图和目的,这些方法的行为似乎完全相同:

List<string> myList = new List<string>();
Foo1(myList);
Foo2(myList);

所以这是我的问题——这两种方法有什么区别?第二种方法似乎更具可读性;是否还有其他我应该注意的差异(生成不同的 IL 等)?提前致谢。

4

5 回答 5

12

几个区别:

  • 如果您再次需要真实类型(例如传递给另一个泛型方法或用于记录),那么泛型方法会更好
  • T可能是一个值类型,但最终仍以通用形式取消装箱。这不太可能是这种情况IList,但对于其他接口来说,这是非常合理的
  • 通用形式允许您指定与实际对象类型不同的具体实现类型。例如,您可能传入一个空引用,但仍想知道哪个实现类型T
  • 它们将以不同的方式进行 JIT 处理;有关更多信息,请参阅 Joe Duffy最近关于泛型的博客文章

当然,这实际上取决于您在做什么......除非您实际上需要了解T该方法中的任何内容,否则通用形式的唯一好处是装箱点。

于 2011-10-25T13:17:42.793 回答
2

如果 Foo2 返回 void,这并不重要。但是假设 Foo2 返回了列表的修改版本。使用 IList 参数,它所能做的最好的事情就是返回另一个 IList。但是使用 IList 约束,假设该类型实现 IList,它可以返回调用者想要的任何类型

于 2011-10-25T13:18:36.863 回答
0

除了所有较低级别的含义之外,当列表被封装并且有修改它的操作时,您正在谈论一个对象并且该列表不应该被公开(在大多数情况下),因此使用泛型是没有意义的并在没有正当理由的情况下公开班级的内部运作。

如果您有一个需要公开列表的数据结构,那么通过泛型指定它往往会使数据存在更容易阅读(恕我直言)。

于 2011-10-25T13:19:56.467 回答
0

重新考虑您的示例,我更喜欢第二种方法。通用方法或类通常在调用者可以使用它们而不是在您的示例中的类型时使用。在这种情况下,您可以避免使用基类(例如object)作为返回值并提供类型安全的返回值。简单样本

public class Foo<T>
{
    public T GetSomething()
    {
        return default(T);
    }
}
于 2011-10-25T13:21:32.873 回答
0

简单的 :

在这里,您给出了一个非常简单的示例:因为您已经给出了顶级接口 ILIST。

但 ,

假设我有一个对象实例。

JimMorrison
JohnLennon
SnowieWhite

他们都来自ILegends

他们都是歌手对象(var歌手=新歌手())

YokOno 也是歌手但不是 Ilegends(嗯……想知道为什么?)

并且您的功能可以采用Singer.

但是您想确保只有 ILegends 有效……所以是您的答案。

于 2011-10-25T13:25:02.283 回答