考虑下面的应用程序代码,有3个重载的扩展方法做同样的输入和输出:
代码:
namespace LINQ_CreatingYourFirstExtensionMethod
{
internal class Program
{
private static void Main(string[] args)
{
string[] aBunchOfWords = {"One", "Two", "Hello", "World", "Four", "Five"};
var iEnuResult = from s in aBunchOfWords
where s.Length == 5
select s;
iEnuResult.Write();
iEnuResult.Write<string>();
iEnuResult.Write<object>();//same effect as above line
Console.ReadKey();
}
}
}
重载的扩展方法Write():
namespace LINQ_CreatingYourFirstExtensionMethod
{
public static class Utils
{
public static void Write(this IEnumerable<object> source) //****1
//public static void Write(this IEnumerable<string> source)//same effects as above line
{
foreach (var item in source)
{
Console.WriteLine(item);
}
}
public static void Write<T>(this IEnumerable<T> source)//****2
{
foreach (var item in source)
{
Console.WriteLine(item);
}
}
public static void Write(this IEnumerable source)//******3
{
foreach (var item in source)
{
Console.WriteLine(item);
}
}
}
}
更新
你能给我一些最简单的插图吗?为什么我需要
<Type>
<Type>
如果没有它可以做同样的事情吗?
UPDATE2:
我没有立刻写出来,因为我认为从问题的背景来看这是显而易见的。
在当前代码中:
iEnuResult.Write();
来电
进入第一种方法:如果要发表评论
public static void Write1<T>(this IEnumerable<T> source)//*****2
然后
iEnuResult.Write1<object>();
无法制作(仅iEnuResult.Write();
)
如果要对第一和第二种方法发表评论,那么3d方法将被
调用iEnuResult.Write();
因此,可以在调用(调用)中使用和不使用<Type>
调用“相同”方法,以及使用和不使用<Type>
的方法定义。
有多种组合(我会说几十种)看似相同的东西,我看不出太多理由。
所以,我想了解这种差异存在的目的是什么,如果有的话
答案 0 :(得分:2)
专注于你的两个问题:
<Type>
<Type>
第二个问题首先。让我重新说一下:我何时定义泛型方法?
当方法定位多个类型时,您将定义一个通用方法,但一次只能一个类型。有两大优势:
IEnumerable<string>
实际上只包含字符串,而不是奇数或其他。这是一种使用没有装箱和拆箱的类型的方法(即分别将值类型转换为object
)。如上所述here:
装箱和拆箱本身就会造成严重的性能损失,但它也会增加托管堆的压力,导致更多的垃圾收集,这对性能来说并不是很好。
如果您只有非类型化方法(3),则枚举无类型IEnumerable
时会将每个字符串装箱(IEnumerator.Current
返回Object
)并再次取消装箱以调用特定类型{ {1}}方法。并且源列表可以包含任何(这在这里无关紧要,但它经常这样做。)
通用方法(2)跳过装箱和拆箱,并且类型安全。
第一种方法强制将任何输入参数(显式或隐式)转换为ToString()
。再次,将发生装箱和拆箱。但另一个令人讨厌的事情是,并不总是存在可用的隐式转换,这会强制该方法的使用者在调用它之前显式进行转换。通过将IEnumerable<object>
更改为select s
可以说明这种效果。如果只有方法1可用,你将获得
实例参数:无法从
select s.Length
转换为'System.Collections.Generic.IEnumerable<int>'
我认为拇指的一般规则是避免类型'System.Collections.Generic.IEnumerable<object>'
(或object
等)的方法参数,除非没有其他选项。
所以简而言之:你的第二种方法是最好的选择,因为它执行任何类型的任务,但避免装箱和拆箱。
现在您的第一个问题。什么时候需要在方法调用中指定泛型类型参数?我可以想到三个原因(可能还有更多):
IEnumerable<object>
的方法参数时,编译器可以通过该参数推断泛型类型。工厂方法通常属于此类别。像T
这样的方法必须通过例如T Create<T>()
调用。 Create<Customer>()
。构造函数是另一个例子:甚至在没有指定类型的情况下也不能调用泛型构造函数。