C#2.0中的泛型约束

本文接着上次对C#2.0泛型的简单介绍,深入讲解泛型的约束特性。通过代码示例展示了无约束时的编译错误及类型转换的问题,引入约束概念,介绍其语法和作用,还说明了约束可以是多个接口、类等的混合,同时指出类型参数使用时的利弊。

上次的一篇翻译里已经简单介绍了一下C#2.0里的泛型。这次我们接着来了解C#泛型的一些特性。

这次介绍一下泛型的约束(Constraints)。

看一下代码:

None.gif public   class  Dictionary < K,V >
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
public void Add(K key, V value)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        dot.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
if (key.CompareTo(x) < 0dot.gif{dot.gif}        // Error, no CompareTo method
InBlock.gif
        dot.gif
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

None.gif

由于K可以任何类型,所以可想而知,key只能使用Object中定义的ToString等方法。代码在编译时就出错了,因为key可能不含有CompareTo方法。

那么如何解决呢?

一种容易想到的办法就是把key转换成IComparable,那么代码就变成了这样:

None.gif public   class  Dictionary < K,V >
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
public void Add(K key, V value)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        dot.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
if (((IComparable)key).CompareTo(x) < 0dot.gif{dot.gif}
InBlock.gif        dot.gif
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

None.gif

这次没有编译时错误了。但是还是要小心,因为实际使用时,如果你使用了一个没有实现IComparable的类型作参数,就会出现InvalidCastException异常。

<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

 

为了提供强编译时检查和减少类型转换,C#2.0泛型引入了约束(Constraints)这个概念,这是一个泛型的可选项。语法是使用where关键字指明约束的类型参数,然后加冒号,再加上类,接口,类型参数等。

 

我们把代码变成了这样:

None.gif public   class  Dictionary < K,V >  where K: IComparable
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
public void Add(K key, V value)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        dot.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
if (key.CompareTo(x) < 0dot.gif{dot.gif}
InBlock.gif        dot.gif
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

None.gif

这样就保证了任何为K类型参数提供的类型都实现了IComparable接口。所以我们的key就可以使用CompareTo方法了。

如果我们在使用时提供了没有实现IComparable接口的类型,就会出现编译时错误。

我们的约束可以不止是一个接口,可以是多个,还可以是跟类或其他约束混合。

请看下面代码:

None.gif public   class  EntityTable < K,E >
None.gif    where K: IComparable
< K > , IPersistable
None.gif    where E: Entity, 
new ()
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
public void Add(K key, E entity)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        dot.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
if (key.CompareTo(x) < 0dot.gif{dot.gif}
InBlock.gif        dot.gif
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

None.gif

对于约束new()可能不好理解。其实这个约束保证了提供给类型参数E的类型必须有一个public,无参的构造器。这样它就允许泛型类使用new E()创建这个类型的实例。

另外指出的是,虽然可以有多个接口作约束,但至多只能有一个类。

 

类型参数必须小心地使用。虽然它提供了更强编译时类型检查,但是却也约束了泛型类型的一些可能的使用情况。比如说,有一个泛型类List<T>约束T实现IComparable接口,这样就可以在List<T>Sort方法中比较项了。然而,就不能为那些没有实现IComparable的类使用IList<T>了,就算Sort方法实际上并没有调用。

参考文献:《CSharp 2.0 Specification》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值