泛型与接口的实际优势
在这种情况下,使用泛型与接口的实际优势是什么:
void MyMethod(IFoo f)
{
}
void MyMethod<T>(T f) : where T : IFoo
{
}
即,您可以在 MyMethod
中执行哪些在非泛型版本中无法执行的操作?我正在寻找一个实际的例子,我知道理论上的差异是什么。
我知道在 MyMethod
中,T 将是具体类型,但尽管如此,我只能将它用作方法体内的 IFoo。那么什么才是真正的优势呢?
What would be a practical advantage of using generics vs interfaces in this case:
void MyMethod(IFoo f)
{
}
void MyMethod<T>(T f) : where T : IFoo
{
}
I.e. what can you do in MyMethod<T>
that you couldn't in the non-generic version? I'm looking for a practical example, I know what the theoretical differences are.
I know that in MyMethod<T>
, T will be the concrete type, but nonetheless I will only be able to use it as an IFoo within the body of the method. So what would be a real advantage?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
T
而不是IFoo
,如果您需要对结果调用 T 的方法IFoo
is a value type, the non-generic version will box the value of the parameter, and boxing can negatively affect performance (especially if you call this method very often)T
rather than aIFoo
, which is convenient if you need to call a method of T on the result好吧,正如其他地方提到的,一个优点是如果返回一个值,则能够返回特定类型的 IFoo 类型。但由于您的问题具体是关于 void MyMethod(IFoo f) 的,所以我想给出至少一种情况的实际示例,其中使用通用方法(对我来说)比接口更有意义。 (是的,我在这方面花了一些时间,但我想尝试一些不同的想法。:D)
有两个代码块,第一个只是通用方法本身和一些上下文,第二个是完整的代码该示例,包括大量注释,包括关于此示例与等效的非通用实现之间可能存在的差异的注释,以及我在实现时尝试但不起作用的各种操作,以及关于我所做的各种选择的注释等。博士等等。
概念
血淋淋的细节
Well, one advantage as mentioned elsewhere, would be the ability to return a specific type of IFoo type if you return a value. But since your question is specifically about
void MyMethod(IFoo f)
, I wanted to give a realistic example of at least one type of situation where using a generic method makes more sense (to me) than the interface. (Yes I spent a bit of time on this, but I wanted to try out some different ideas. :D)There are two blocks of code, the first is just the generic method itself and some context, the second is the full code for the example, including lots of comments ranging from notes on possible differences between this and an equivalent non-generic implementation, as well as various things I tried while implementing that didn't work, and notes on various choices I made, etc. TL;DR and all that.
Concept
Gory Details
做这样的事情更容易:
此外,当您引入更多接口时,泛型对于调用者可能会更加“温和”。例如,您可以从 2 个接口继承一个类并直接传递它,就像这样......
而“仅接口”方法将需要一个“中间”接口(
IFooBar
)。 。Doing things like these is easier:
Also, as you introduce more interfaces, generics may be more "gentle" to callers. For example, you can inherit a class from 2 interfaces and pass it directly, like this...
...while "interface-only" method would require an "intermediary" interface (
IFooBar
)...2年后我发现了一个非常简单又有用的案例。考虑这个常见模式:
我一直想编写一个辅助方法,以避免为每个字段编写所有这些样板:
不幸的是,这在 C# 中是非法的,因为您不能使用 ref 参数的接口,您必须使用您的具体类型会通过,没有别的。因此,您必须为要处理的每种类型的字段编写不同的方法。哦等等,这正是泛型为您所做的:
现在一切都按预期运行!
2 years later I found a very simple and useful case. Consider this common pattern:
I've always wanted to write a helper method to avoid having to write all this boilerplate for every field:
Unfortunately this is illegal in C# because you cannot use an interface for ref parameters, you must use the concrete type you'll pass in and nothing else. So you'd have to write a different method for every single type of field you want to dispose. Oh wait that's exactly what generics do for you:
Now everything works as intended!
接口方法将为您提供一个
IFoo
类型的f
,而通用版本将为您提供一个类型T
,其约束为T
必须实现IFoo
。第二种方法允许您根据
T
进行某种查找,因为您有一个具体的类型可供使用。The interface method will supply you an
f
of typeIFoo
, whereas the generic version will supply you a typeT
with the constraint thatT
has to implementIFoo
.The second method would allow you to have some kind of lookup depending on
T
, as you have a concrete type to work with.在这种特定情况下,没有任何好处。一般来说,您不会在方法级别指定这一点,而是在类级别指定。例如,
请注意,我们需要 T 实现 IFoo,因为 Add 方法需要调用 IFoo 实现的 DoSomethingImportantMethod。
但请注意,在 Get 方法中,我们将返回此类的最终用户提供的 T,而不是普通的旧 IFoo,这减轻了开发人员始终强制转换为其实际具体 T 的需要。
示例:
请注意,如果我只是返回 IFoo,那么我必须在最后一行执行此操作:
In this particular case, there is no benefit. In general you wouldn't specify this at a method level, but at a class level. E.g.,
Notice that we require T to implement IFoo because of the Add method where we need to call the DoSomethingImportantMethod implemented by IFoo.
But notice in the Get method that we will return the T provided by end user of this class instead of a plain old IFoo, which alleviates the need for the developer to always cast to their actual concrete T.
Example:
Note that if I was just returning an IFoo, then I would have to do this at the last line instead:
参考上面报告的基准
运行Visual Studio 2015 中的代码,直接调用和通过接口的结果大致相同:
用于基准测试的代码(来自 http://pastebin.com/jx3W5zWb )是:
referring to the benchmark reported above
running the code in Visual Studio 2015 the result are roughly equivalent between Direct call and Through interface:
the code used to benchmark (from http://pastebin.com/jx3W5zWb ) is:
通用版本允许您使用任何类型作为 T - 由于某种原因,您可以通过使用 where 子句来限制它,而您的非通用版本仅支持实现 IFoo 的东西。
另一个(也许更好)问题是 - 这两个选项等效吗?
The generic version allows you to use any type as T - which you for some reason restricted back by using the where clause, whereas your non-generic version supports only something implementing IFoo.
Another (maybe better) question is - are these two options equivalent?