泛型方法类型推断
有以下代码:
static List MakeList(T first,T second);
{
......
}
List list = MakeList("a1","b1");
可以简写成:
List list = MakeList("a1","b1");
在这里就使用到了泛型类型推断,但是类型推断只适用于泛型方法。
默认值表达式
在一个泛型类当中,你如果要知道该类型参数的默认值,不能使用null,因为类型参数可能被约束为值类型,你也不能使用0,因为也有可能被约束为引用类型。在C#2当中提供了默认值表达式default(T),就可以返回类型实参的默认值。
static int CompareToDefault(T value) where T : IComparable
{
return value.CompareTo(default(T));
}
Console.WriteLine(ComparaToDefault("x")); //1
Console.WriteLine(ComparaToDefault(10)); //1
Console.WriteLine(ComparaToDefault(0)); //0
Console.WriteLine(ComparaToDefault(-10)); //-1
Console.WriteLine(ComparaToDefault(DateTime.MinValue)); //0
由CompareTo文档指出,所有引用类型的值都大于null,所以返回1,CompareTo,如果比较的值比自己大则为1,相等则为0,小于则为-1。
不过如果传入的是null,以上代码会如预期的抛出NullReferenceException异常,我们可以使用IComparer。
泛型比较
如果一个类型参数是未被约束的,那么只能在泛型类直线中对该类型的值与null进行比较的时候才可以使用!=、==操作符。
如果类型参数被约束为值类型,那么就完全不能使用!=、==操作符。
如果他只是一个引用类型,则只能进行简单的引用比较,可以使用!=、==操作符。
如果他被进一步约束成继承自某个重载了的!=、==操作符的特定类型(即转换类型约束),就会使用重载操作符。
如果调用者指定的类型实参恰巧也进行了重载,那么这个重载操作符是不会使用的
static bool AreReferenceEqual(T first,T second) where T : class
{
return first == second;
}
string name = "Jon";
string intro1 = "Hello " + name;
string intro1 = "Hello " + name;
Console.WriteLine(intro1 == intro2);
Console.WriteLine(AreReferenceEqual(intro1,intro2));
在这里,第一行输出为True,是因为这里使用的是string重载过的比较操作符,用于比较两个字符串是否相等。
而第二行输出为False,是因为在编译AreReferenceEqual的时候,编译器根本不知道有哪些重载可用,因为我们约束的是class,所以相当于传入的类型实参是object。
不仅仅是操作符的时候,编译器会在编译未绑定泛型类型的时候就解析好所有方法重载,而不是等到执行时。
在对值进行比较的时,有两个相当有用的类,分别是EqualityComparer和Comparer,他们分别实现了IEqulalityComparer和IComparaer这两个接口。这两个类分别有一个Default的属性能够返回一个实现,能为特定的特定的类型才去正确的比较操作。
IComparaer和IComparable用于排序,判断某个值是小于、等于、还是大于另一个值。
IEqualityComparer和IEquatable则是通过某种标准来比较两个项的相等型,或者查找某个项的散列值。
IComparaer和IEqualityComparer的实例能够比较两个不同的值。
IComparable和IEquatable只能比较它们本身和其他的值。
实现类似元组的泛型对值
public sealed class Pair : IEquatable> //这里我们实现了IEquatable,提供了一个强类型的API(Equals方法),可以避免不必要的运行时类型检查。
{
// 生成一个默认的比较器,可以自动处理null值的情况
private static readonly IEqualityComparer FirstComparer = EqualityComparer.Default;
private static readonly IEqualityComparer SecondComparer = EqualityComparer.Default;
private readonly T1 first;
private readonly T2 second;
public Pair(T1 first, T2 second)
{
this.first = first;
this.second = second;
}
public T1 First { get { return first; } }
public T2 Second { get { return second; } }
public bool Equals(Pair other)
{
return other != null && FirstComparer.Equals(this.First, other.first) &&
SecondComparer.Equals(this.Second, other.Second);
}
public override bool Equals(object obj)
{
return Equals(obj as Pair);
}
public override int GetHashCode()
{
return FirstComparer.GetHashCode(first) * 37 + SecondComparer.GetHashCode(second);
}
// public static Pair Of(T1 first,T2 second)
public static Pair Of(T1 first,T2 second)
{
return new Pair(first, second);
}
}