规范化通常(在计算机科学之外)表示“使某些东西成为现实”。
在编程中,如果我们能够以语言本身访问有关该信息的信息,那么这些东西就可以得到具体化。
对于两个完全与非泛型无关的示例,C#确实已经实现了某些内容,而C#还没有实现这些内容,让我们来研究方法和内存访问。
OO语言通常具有方法,(许多语言虽然没有绑定到类,但没有相似的功能)。这样,您就可以用这种语言定义方法,进行调用,也许覆盖它,等等。并非所有此类语言都可以让您实际将方法本身作为程序数据处理。C#(实际上是.NET而不是C#)确实允许您使用MethodInfo
表示方法的对象,因此在C#中方法被重新定义。C#中的方法是“一流的对象”。
所有实用语言都有一些访问计算机内存的方法。在像C这样的低级语言中,我们可以直接处理计算机使用的数字地址之间的映射,因此之类的int* ptr = (int*) 0xA000000; *ptr = 42;
是合理的(只要我们有充分的理由怀疑0xA000000
以这种方式访问内存地址就可以了)炸掉东西)。在C#中,这是不合理的(我们可以在.NET中强制使用它,但是随着.NET内存管理的发展,它不太有用)。C#没有统一的内存地址。
因此,正如被剥夺的意思是“实现”,“被确定的类型”一样,我们可以用所讨论的语言“谈论”这种类型。
在泛型中,这意味着两件事。
一个是List<string>
就是原样string
还是原样int
。我们可以比较该类型,获取其名称并进行查询:
Console.WriteLine(typeof(List<string>).FullName); // System.Collections.Generic.List`1[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]
Console.WriteLine(typeof(List<string>) == (42).GetType()); // False
Console.WriteLine(typeof(List<string>) == Enumerable.Range(0, 1).Select(i => i.ToString()).ToList().GetType()); // True
Console.WriteLine(typeof(List<string>).GenericTypeArguments[0] == typeof(string)); // True
这样的结果是我们可以在方法本身内“讨论”通用方法(或通用类的方法)参数的类型:
public static void DescribeType<T>(T element)
{
Console.WriteLine(typeof(T).FullName);
}
public static void Main()
{
DescribeType(42); // System.Int32
DescribeType(42L); // System.Int64
DescribeType(DateTime.UtcNow); // System.DateTime
}
通常,这样做太多是“可笑的”,但是有很多有用的情况。例如,查看:
public static TSource Min<TSource>(this IEnumerable<TSource> source)
{
if (source == null) throw Error.ArgumentNull("source");
Comparer<TSource> comparer = Comparer<TSource>.Default;
TSource value = default(TSource);
if (value == null)
{
using (IEnumerator<TSource> e = source.GetEnumerator())
{
do
{
if (!e.MoveNext()) return value;
value = e.Current;
} while (value == null);
while (e.MoveNext())
{
TSource x = e.Current;
if (x != null && comparer.Compare(x, value) < 0) value = x;
}
}
}
else
{
using (IEnumerator<TSource> e = source.GetEnumerator())
{
if (!e.MoveNext()) throw Error.NoElements();
value = e.Current;
while (e.MoveNext())
{
TSource x = e.Current;
if (comparer.Compare(x, value) < 0) value = x;
}
}
}
return value;
}
这样做并不能对TSource
不同类型的行为进行多种比较(通常是一个迹象,表明您根本不应该使用泛型),但确实在可以使用的类型的代码路径之间进行了分割null
(如果返回,null
则返回没有找到元素,并且如果比较的元素之一是,则不能进行比较以找到最小值;如果不能找到null
类型的代码路径,则不能进行比较null
(如果没有找到元素,则应该抛出该错误,并且不必担心null
元素的可能性))。
由于TSource
该方法是“真实的”,因此可以在运行时或扩展时间(通常是扩展时间,当然上述情况会在扩展时间这样做,并且不为未采用的路径生成机器代码)进行此比较。针对每种情况分别使用该方法的“实际”版本。(尽管作为优化,机器代码对于不同的引用类型类型参数共享给不同的方法,因为它可以不影响它,因此我们可以减少机器代码的数量)。
(除非您也处理Java,否则在C#中谈论泛型类型的化是不常见的,因为在C#中,我们只是将这种化化视为理所当然;所有类型都是化化的。在Java中,非泛型类型被称为化化是因为,因为是它们和通用类型之间的区别)。