1.默认值表达式
如果已经明确了要处理的类型,也就知道了它的“默认”值。不知道要引用的类型,就不能直接指定默认值。不能使用null,因为它可能不是一个引用类型,不能使用0,因为它可能不是数值类型。虽然很少需要用到默认值,但它偶尔还是有用的。Dictionary
为了满足这方面的要求,c#2提供了默认值表达式。虽然c#语言规范没有说他是一个操作符,但可以把它看做是与typeof相似的操作符,只是返回值不一样罢了。
复制代码 代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 默认值表达式
{
class Program
{
static int CompareToDefault
where T : IComparable
{
return value.CompareTo(default(T));
}
static void Main(string[] args)
{
Console.WriteLine(CompareToDefault("x"));
Console.WriteLine(CompareToDefault(10));
Console.WriteLine(CompareToDefault(0));
Console.WriteLine(CompareToDefault(-10));
Console.WriteLine(CompareToDefault(DateTime.MinValue));
}
}
}
运行结果:
在上述代码中,我们为泛型方法使用了3种不同的类型:string,int和DateTime. CompareToDefault方法规定只能使用实现了IComparable
如果传递的参数是null,上述代码会抛出NullReferenceException异常。
2.直接比较
虽然上述代码演示了如何进行比较,但我们并不是总是愿意限制我们自己的类型来实现IComparable
如果一个类型是未约束的,就可以使用==和!=操作符,但只能将该类型的值与null进行比较。不能直接比较两个T类型的值(会报错,无法通过编译),如果类型实参是一个引用类型,会进行正常的引用比较。如果为T提供的类型实参是一个非可空值类型,与null进行比较总是不相等(这样一来,JIT编译器就可以移除这个比较)。如果类型实参是可空值类型,那么就会自然而然的与类型的空值进行比较。
如果一个类型参数被约束成值类型,就完全不能使用==和!=。如果被约束成引用类型,那么具体执行的比较将完全取决于类型参数被约束成什么类型。如果它只是一个引用类型,那么执行的是简单的引用比较。如果被进一步约束成继承自某个重载了==和!=操作符的特定类型,就会使用重载运算符。但要注意,假如调用者指定的类型实参恰巧也进行了重载,那么这个重载操作符是不会使用的。
复制代码 代码如下:
using System.Text;
using System.Threading.Tasks;
namespace 直接比较实现
{
class Program
{
static bool AreReferencesEqual
where T:class
{
return first == second;
}
static void Main(string[] args)
{
string name = "Joy";
string intro1 = "My name is "+name;
string intro2 = "My name is "+name;
Console.WriteLine(intro1==intro2);
Console.WriteLine(AreReferencesEqual(intro1,intro2));
}
}
}
运行结果为:
虽然string 重载了==,但在执行的比较中是不会用这个重载的。基本上,在说编译AreReferencesEqual
并非只有操作符才有这个问题,遇到泛型类型时,编译器会在编译未绑定时就解析好所有方法重载,而不是等到执行时,才去为每个可能的方法调用重新考虑是否存在更具体的重载。例如,Console.WriteLine(default(t));这个语句总是被解析成Console.WriteLine(object object),即使为T传递的类型恰好就是string,也不会调用Console.WriteLine(string value),这好比普通方法重载是发生在编译时,而不是执行时。
需要对值进行比较时,有两个相当有用的类,他们是EqualityComparer
说明:泛型比较接口 共有四个主要的泛型接口可用于比较。IComparer
如果换一种方式来划分这四个接口,IComparer
3.一个完整的比较实例,表示一对值
这是一个完整的实例,它实现了一个有用的泛型类型,也就是一个Pair
除了提供属性来访问值本身之外,我们还覆盖了Equals和GetHashCode方法,从而使这个类型的实例能很好的作为字典中的键来使用。
pair
复制代码 代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 表示一对值的泛型类
{
public sealed class Pair
{
private static readonly IEqualityComparer
private static readonly IEqualityComparer
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
{
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);
}
}
}
Pair
复制代码 代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 表示一对值的泛型类
{
public static class Pair
{
public static Pair
{
return new Pair
}
}
}
主体方法
复制代码 代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 表示一对值的泛型类
{
class Program
{
static void Main(string[] args)
{
Pair
Pair
Pair
bool c = pair1.Equals(pair2);
bool d = pair2.Equals(pair3);
System.Console.WriteLine(c);
System.Console.WriteLine(d);
System.Console.WriteLine(pair2.GetHashCode());
}
}
}
运行结果



