接口作为类型约束和接口作为参数之间的区别?

发布于 2024-12-12 08:20:37 字数 532 浏览 0 评论 0原文

如果我想创建一个将 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

一个人练习一个人 2024-12-19 08:20:37

有几个区别:

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

当然取决于你在做什么......除非你实际上需要了解方法中的 T 的任何信息,通用形式的唯一好处是装箱 观点。

A couple of differences:

  • If you ever need the real type again (e.g. to pass to another generic method or for logging) then the generic method will be better
  • 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 for IList, but for other interfaces it's highly plausible
  • The generic form allows you to specify a concrete implementation type which is different from the actual object type. For example, you might pass in a null reference but still want to know which implementation type T is
  • They will be JITted differently; see Joe Duffy's recent blog post on generics for more information

It 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.

海的爱人是光 2024-12-19 08:20:37

如果 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

韶华倾负 2024-12-19 08:20:37

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

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

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).

背叛残局 2024-12-19 08:20:37

考虑到你的例子,我更喜欢第二种方法。当调用者可以将通用方法或类与您的示例中的多种类型一起使用时,通常会使用通用方法或类。在这种情况下,您可以避免使用基类(例如object)作为返回值并提供类型安全的返回值。
简单样本上

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

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

public class Foo<T>
{
    public T GetSomething()
    {
        return default(T);
    }
}
风吹雪碎 2024-12-19 08:20:37

简单:

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

但是,

假设我有一个对象实例。

JimMorrison
JohnLennon
SnowieWhite

它们都来自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.

JimMorrison
JohnLennon
SnowieWhite

they are all from ILegends.

they are all singers objects ( var singer = new Singer())

YokOno is also a singer but not Ilegends ( 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文