如果我想创建一个方法,将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等)?提前谢谢。
答案 0 :(得分:11)
有几点不同:
T
可以是值类型,但最终仍会以通用形式取消装箱。 <{1}}不太可能出现这种情况,但对于其他界面来说,这是非常合理的IList
是这当然取决于你正在做什么......除非你真的需要知道方法中T
的任何内容,否则通用形式的唯一好处就是装箱点。
答案 1 :(得分:2)
如果Foo2返回void,则无关紧要。但是假设Foo2返回了列表的修改版本。使用IList参数,它能做的最好就是返回另一个IList。但是使用IList约束,它可以返回调用者想要的任何类型,假设该类型实现IList
答案 2 :(得分:0)
除了所有较低级别的含义之外,当列表被封装并且有修改它的操作时,你谈论的是一个对象而且这个列表不应该暴露(在大多数情况下),因此使用泛型是毫无意义的,没有正当理由暴露出类的内部运作。
如果您有一个需要公开列表的数据结构,那么通过泛型指定它往往会使数据存在更容易阅读(恕我直言)。
答案 3 :(得分:0)
重新说明你的例子我更喜欢第二种方法。当调用者可以使用多个类型时,通常使用通用方法或类,如示例中所示。在这种情况下,您可以避免使用基类(例如object
)作为返回值并提供类型安全返回值。
简单的样本
public class Foo<T>
{
public T GetSomething()
{
return default(T);
}
}
答案 4 :(得分:0)
简单:
这里给出了一个非常简单的例子:因为你已经给了顶级接口ILIST。
但是,
让我说我有一个对象的实例。
JimMorrison
JohnLennon
SnowieWhite
他们全都来自ILegends
。
他们都是歌手的对象(var singer = new Singer())
YokOno
也是歌手,但不 Ilegends
(mmmm ......想知道为什么?)
,您的功能可以Singer
。
但你想确保只有ILegeneds才有效...... 所以这里是你的答案。