接口作为类型约束与接口作为参数的区别

本文关键字:接口 区别 参数 约束 类型 | 更新日期: 2023-09-27 18:12:14

如果我想创建一个以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不同等)?

接口作为类型约束与接口作为参数的区别

几个区别:

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

这当然取决于你在做什么…除非您确实需要了解方法中的T,否则通用表单的唯一好处就是装箱点。

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

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

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

重新考虑您的示例,我更喜欢第二种方法。泛型方法或类主要用于调用者可以将它们用于多种类型(如您的示例)的情况。在这种情况下,您可以避免基类(例如object)作为返回值,并提供类型安全的返回值。简单示例

public class Foo<T>
{
    public T GetSomething()
    {
        return default(T);
    }
}

Simple:

这里你给出了一个非常简单的例子:因为你已经给出了顶部接口ILIST。

but,

假设我有一个对象实例

JimMorrison
JohnLennon
SnowieWhite

它们都来自ILegends

它们都是singer对象(var singer = new singer ())

YokOno也是一个歌手,但不是 Ilegends (mmmm…想知道为什么吗?)

和你的函数可以取Singer

但是你想确保只有ILegeneds是有效的…所以这里是你的答案