接口作为类型约束和接口作为参数之间的区别?
如果我想创建一个将 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 等)?提前致谢。
If I wanted to create a method that takes an instance of IList
as a parameter (or any other interface, but let's use IList
as an example), I could create a generic method with a type constraint, e.g.:
public static void Foo1<T>(T list) where T : IList
{
}
Alternatively, I could create a method that takes an IList
parameter directly:
public static void Foo2(IList list)
{
}
For all intents and purposes, it seems like these methods behave exactly the same:
List<string> myList = new List<string>();
Foo1(myList);
Foo2(myList);
So here's my question -- what's the difference between these two approaches? It seems like the second approach is slightly more readable; are there any other differences I should be aware of (different IL being generated, etc)? Thanks in advance.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
有几个区别:
T
可能是值类型,但最终仍以通用形式拆箱。对于IList
来说,这种情况不太可能发生,但对于其他接口来说,这是非常合理的。T
是哪个实现类型当然取决于你在做什么......除非你实际上需要了解方法中的
T
的任何信息,通用形式的唯一好处是装箱 观点。A couple of differences:
T
could be a value type and still end up being unboxed in the generic form. It's pretty unlikely that this would be the case forIList
, but for other interfaces it's highly plausibleT
isIt really depends on what you're doing of course... unless you actually need to know anything about
T
within the method, the only benefit to the generic form is the boxing point.如果 Foo2 返回 void,那并不重要。但假设 Foo2 返回了列表的修改版本。对于 IList 参数,它最多可以返回另一个 IList。但有了 IList 约束,它可以返回调用者想要的任何类型,假设该类型实现了 IList
if Foo2 returns void, it doesn't really matter. But suppose Foo2 returned a modified version of the list. With an IList parameter, the best it could do is return another IList. But with an IList constraint, it could return any type the caller wants assuming that type implements IList
除了所有较低级别的含义之外,当封装列表并且有修改它的操作时,您正在谈论一个对象,并且该列表不应该被公开(在大多数情况下),因此使用泛型是没有意义的并在没有正当理由的情况下揭露班级的内部运作。
如果您有一个需要公开列表的数据结构,那么通过泛型指定它往往会使数据的存在更易于阅读(恕我直言)。
Aside from all the lower-level implications, when the list is encapsulated and there are operations to modify it, you're talking about an object and this list shouldn't be exposed (in most cases), therefore the use of generics are pointless and expose, without a valid reason, the inner workings of the class.
If you have a data structure that needs to expose the list, then specifying it by generics tend to make the data presence easier to read (IMHO).
考虑到你的例子,我更喜欢第二种方法。当调用者可以将通用方法或类与您的示例中的多种类型一起使用时,通常会使用通用方法或类。在这种情况下,您可以避免使用基类(例如
object
)作为返回值并提供类型安全的返回值。简单样本上
Reagrding your example I would prefer the second approach. Generic methods or classes are mostly used when the caller can use them with more than on type as in your example. In this case you can avoid a base class (e.g.
object
) as return value and provide type safe return values.On simple sample
简单:
在这里你给出了一个非常简单的例子:因为你已经给出了顶级接口ILIST。
但是,
假设我有一个对象实例。
它们都来自
ILegends
。它们都是歌手对象 ( var seller = new Singer())
YokOno
也是歌手,但不是Ilegends
(嗯……想知道为什么?)并且您的函数可以采用
Singer
。但你想确保只有 ILegends 才有效......
所以这里就是你的答案。
Simple :
here you gave a pretty easy example : since you already gave the top interface ILIST.
but ,
lets say i have an instanc Of Objects.
they are all from
ILegends
.they are all singers objects ( var singer = new Singer())
YokOno
is also a singer but notIlegends
( mmmm ... wonder why?)and your function can take
Singer
.but you want to make sure that only ILegeneds will be valid...
so here is your answer.