对泛型类型进行判等(比较)

这个问题似乎已经讨论过很多次了,就当是给自己做笔记,我再总结一次。

问题背景是我在给IEnumerable<T>添加一个扩展方法时,要判断两个元素是否相等,假设分别是left和right,类型为T,T没有任何约束。首先自然而然地写出了这样的代码:

if  (left  ==  right) // <-- Compile error
{
dot.gif
}

更自然地,我得到了一个编译错误,因为类型T上根本没有定义"=="运算符。

后来在网上看到,很多人在这个时候会采用添加约束"where T: IComparable<T>"的方法(称为方案1)。这是一个解决方案,但明显太cuo了。首先,大多数类都不实现IComparable<T>接口;其次,那些实现了IComparable接口的怎么办?而且实际上我根本不需要比较大小,只是比较是否相等,更进一步,我只需要判断对象是否是同一个,即是否是ReferenceEquals的。由此我们可以想到,object类实现了一个静态Equals (obj, obj)方法,对于引用类型,它相当于ReferenceEquals方法,对于值类型,它会进行按位比较。这就是所谓“默认的比较方式”。于是最终代码如下:

if  ( object .Equals (left, right)) // Solution 2.
{
dot.gif
}
这是方案2.

但在当时我没想到那么多,我用了一个比较ws的方式,我把比较操作外包出去了:

 

public  IEnumerable < T >  DemoMethod<T> ( this  IEnumerable < T >  source,
                      Func
< T, T,  bool >  equalityComparison)
{
dot.gif
    
if  (equalityComparison (left, right))
    {
    dot.gif
    }
dot.gif
}

然后在调用方:

foreach  (var item  in   " abc " .DemoMethod ((x, y)  =>  x  ==  y)) 
// string实现IEnumerable<char>接口,而char支持"=="操作符
{
dot.gif
}

这是方案3.

此外,参考List<T>.Sort()方法的实现,可以知道有个Comparer<T>.Default的默认比较器,其上有个Compare方法,于是得到方案4:

if  (Comparer < T > .Default.Compare (left, right)  ==   0 )
{
dot.gif
}
然而当无法取得所比较类型的默认比较器时,在Compare方法上会引发ArgumentException异常。

三种方案比较,显然方案1需要添加约束,太不灵活;方案2可以应付大多数常规情况,编码比较方便,但如果需要比较大小则无法实现,这时可以考虑方案4,但由于实现了默认比较器的类型实在很少,方案4也是个鸡肋;方案3则最灵活,可以由方法用户自行指定比较方案。可谓2、3皆有所长,可以作为重载都写上。事实上,方案2可以实现为对方案3的调用:

public  IEnumerable < T >  DemoMethod<T> ( this  IEnumerable < T >  source)
{
    source.DemoMethod (
object .Equals);
}

 

那能不能再进一步,在C#4.0中可选参数的支持下,不用重载,只写一个方法就行了呢?

public  IEnumerable < T >  DemoMethod < T >  ( this  IEnumerable < T >  source,
                      Func
< T, T,  bool >  equalityComparison = object.Equals)
// Compile error: Default parameter value for 'equalityComparison' must be a compile-time constant

实验结果是不行,因为可选参数的默认值必须是编译时常量,而一个方法的引用(其实应该是函数地址吧)在编译时是无法确定的。

转载于:https://www.cnblogs.com/Gildor/archive/2009/09/05/1560671.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值