声明
本文内容来自微软 MVP solenovex 的视频教程——真会C#? - 第3章 泛型简介(完结),大致和第 2 课—— 3.9 泛型约束、子类、自引用、静态数据、转换 对应。可在 GitHub 中查看 C# 视频教程的配套PPT
本文主要包括以下内容:
- 泛型的约束
- 泛型类型的子类
- 自引用的泛型声明
- 静态数据
- 类型参数和转换
泛型的约束
默认情况下,泛型的类型参数(parameter)可以是任何类型的。如果只允许使用特定的类型参数(argument),就可以指定约束。泛型的约束可以作用于类型或方法的定义。
where T : base-class // Base-class constraint
where T : interface // Interface constraint
where T : class // Reference-type constraint
where T : struct // Value-type constraint (excludes Nullable types)
where T : new() // Parameterless constructor constraint
where U : T // Naked type constraint
泛型类型的子类
泛型 class 可以有子类,在子类里,可以继续让父类的类型参数保持开放。
class Stack<T> {...}
class SpecialStack<T> : Stack<T> {...}
在子类里,也可以使用具体的类型来关闭(封闭)父类的类型参数。class IntStack : Stack<int> {...}
子类型也可以引入新的类型参数。
class List<T> {...}
class KeyedList<T,TKey> : List<T> {...}
技术上来讲,所有子类的类型参数都是新鲜的。你可以认为子类先把父类的类型参数(argument)给关闭了,然后又打开了。为这个先关闭后打开的类型参数(argument)带来新的名称或含义。
class List<T> {...}
class KeyedList<TElement,TKey> : List<TElement> {...}
自引用的泛型声明
在封闭类型参数(argument)的时候,该类型可以把它自己作为具体的类型。
public interface IEquatable<T> { bool Equals (T obj); }
public class Balloon : IEquatable<Balloon>
{
public string Color { get; set; }
public int CC { get; set; }
public bool Equals (Balloon b)
{
if (b == null) return false;
return b.Color == Color && b.CC == CC;
}
}
class Foo<T> where T : IComparable<T> { ... }
class Bar<T> where T : Bar<T> { ... }
静态数据
针对每一个封闭类型,静态数据是唯一的。
class Bob<T> { public static int Count; }
class Test
{
static void Main()
{
Console.WriteLine (++Bob<int>.Count); // 1
Console.WriteLine (++Bob<int>.Count); // 2
Console.WriteLine (++Bob<string>.Count); // 1
Console.WriteLine (++Bob<object>.Count); // 1
}
}
类型参数和转换
C# 的转换操作符支持下列转换:
- 数值转换
- 引用转换
- 装箱拆箱转换
- 自定义转换
决定采用的是哪种转换,发生在编译时,根据已知类型的操作数来决定。
StringBuilder Foo<T> (T arg)
{
if (arg is StringBuilder)
return (StringBuilder) arg; // Will not compile
...
}
StringBuilder Foo<T> (T arg)
{
StringBuilder sb = arg as StringBuilder;
if (sb != null) return sb;
...
}
return (StringBuilder) (object) arg;
int Foo<T> (T x) => (int) x; // Compile-time error
int Foo<T> (T x) => (int) (object) x;
参考
Generics (C# Programming Guide)
Generic Methods (C# Programming Guide)
Generic Classes (C# Programming Guide)