接口作为类型约束与接口作为参数的区别
本文关键字:接口 区别 参数 约束 类型 | 更新日期: 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
来说是不太可能的,但对于其他接口来说,这是非常合理的 通用形式允许您指定一个具体的实现类型,该类型与实际对象类型不同。例如,您可能传入一个空引用,但仍然想知道 - 它们将以不同的方式被编译;有关更多信息,请参阅Joe Duffy最近关于泛型的博文
T
是哪个实现类型这当然取决于你在做什么…除非您确实需要了解方法中的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是有效的…所以这里是你的答案