An Introduction to C# Generics[5]

[入库:2005年8月18日] [更新:2007年3月25日]

本文简介:选择自 13121982 的 blog

generic type metadata so that the client-side compiler can take advantage of them as well. the
client-side compiler only allows the client developer to use types that comply with the constraints, thus
enforcing type safety.
an example will go a long way to explain the need and use of constraints. suppose you would like to add
indexing ability or searching by key to the linked list of code block 3:
public class linkedlist<k,t>
{
t find(k key)
{...}
public t this[k key]
{
get{return find(key);}
}
}
this allows the client to write the following code:
linkedlist<int,string> list = new linkedlist<int,string>();
list.addhead(123,"aaa");
list.addhead(456,"bbb");
string item = list[456];
debug.assert(item == "bbb");
to implement the search, you need to scan the list, compare each node's key with the key you're looking
for, and return the item of the node whose key matches. the problem is that the following
implementation of find() does not compile:
t find(k key)
{
node<k,t> current = m_head;
while(current.nextnode != null)
{
if(current.key == key) //will not compile
break;
else
current = current.nextnode;
}
return current.item;
}
the reason is that the compiler will refuse to compile this line:
if(current.key == key)
the line above will not compile because the compiler does not know whether k (or the actual type
supplied by the client) supports the == operator. for example, structs by default do not provide such an
implementation. you could try to overcome the == operator limitation by using the icomparable
interface:
public interface icomparable
{
int compareto(object obj);
}
compareto() returns 0 if the object you compare to is equal to the object implementing the interface,
so the find() method could use it as follows:
if(current.key.compareto(key) == 0)
unfortunately, this does not compile either because the compiler has no way of knowing whether k (or
the actual type supplied by the client) is derived from icomparable.
you could explicitly cast to icomparable to force the compiler to compile the comparing line, except
doing so is at the expense of type safety:
if(((icomparable)(current.key)).compareto(key) == 0)
if the type the client uses does not derive from icomparable, it results in a run-time exception. in
addition, when the key type used is a value type instead of the key type parameter, you force a boxing
of the key, and that may have some performance implications.
derivation constraints
in c# 2.0 you use the where reserved keyword to define a constraint. use the where keyword on the
generic type parameter followed by a derivation colon to indicate to the compiler that the generic type
parameter implements a particular interface. for example, here is the derivation constraint required to
implement the find() method of linkedlist:
public class linkedlist<k,t> where k : icomparable
{
t find(k key)
{
node<k,t> current = m_head;
while(current.nextnode != null)
{
if(current.key.compareto(key) == 0)
break;
else
current = current.nextnode;
}
return current.item;
}
//rest of the implementation
}
note that even though the constraint allows you to use icomparable, it does not eliminate the boxing
penalty when the key used is a value type, such as an integer. to overcome this, the
system.collections.generics namespace defines the generic interface icomparable<t>:
public interface icomparable<t>
{
int compareto(t other);
}
you can constrain the key type parameter to support icomparable<t> with the key's type as the type
parameter, and by doing so you gain not only type safety but also eliminate the boxing of value types
when used as keys:
public class linkedlist<k,t> where k : icomparable<k>
{...}
in fact, all the types that supported icomparable in .net 1.1 support icomparable<t> in .net 2.0.
this enables the use for keys of common types such as int, string, guid, datetime, and so on.
in c# 2.0, all constraints must appear after the actual derivation list of the generic class. for example,
if linkedlist derives from the ienumerable<t> interface (for iterator support), you would put the
where keyword immediately after it:
public class linkedlist<k,t> : ienumerable<t> where k : icomparable<k>
{...}
note that the constraint appears where the generic type parameter k is defined, at the declaration line of
the linkedlist class. this permits the class linkedlist to treat the generic type parameter k as
implementing icomparable<t> with k as the type parameter. you will also get intellisense support on
the methods of interfaces you constrain.

本文关键:An Introduction to C# Generics
  相关方案
Google
 

本站最佳浏览方式为 分辨率 1024x768 IE 6.0(或更高版本的 IE浏览器)

go top