泛型--约束

 

9.5 约束

有的时候,您必须确保添加进泛型列表中的元素拥有某些约束(例如,它们从一个给定的基类继承或它们实现了指定的接口)。在下面的例子中,我们实现了一个简单的可排序的单链表。链表由多个Node组成,每个Node必须保证添加进去的元素实现了IComparer接口。您可以这样声明:

public class Node<T> : IComparable<Node<T>> where T : IComparable<T>

这句代码定义了一个泛型Node,它操作类型TNode中的T实现了IComparable<T>接口,这意味着两个NodeT可以进行对比。Node类通过约束(where T : IComparable<T>)来操作那些实现了IComparable接口的类型。因此您可以使用任何类型来替代T,只要那种类型实现了IComparable接口

9-12举例说明了完整的接口实现,并进行分析如下。

9-12 使用约束


using System;
using System.Collections.Generic;

namespace UsingConstraints
{
    
public class Employee : IComparable<Employee>
    {
        
private string name;
        
public Employee(string name)
        {
            
this.name = name;
        }
        
public override string ToString()
        {
            
return this.name;
        }
        
//实现接口
        public int CompareTo(Employee rhs)
        {
            
return this.name.CompareTo(rhs.name);
        }
        
public bool Equals(Employee rhs)
        {
            
return this.name == rhs.name;
        }
    }
    
//节点必须实现Node<T>的IComparable接口。
    
//通过where关键字约束Node只接收实现了IComparable接口的项
    public class Node<T> : IComparable<Node<T>> where T : IComparable<T>
    {
        
//成员变量
        private T data;
        
private Node<T> next = null//下一个节点
        private Node<T> prev = null//前一个节点
        
//构造方法
        public Node(T data)
        {
            
this.data = data;
        }
        
//属性
        public T Data 
        { 
            
get { return this.data; } 
        }
        
public Node<T> Next
        {
            
get { return this.next; }
        }
        
public int CompareTo(Node<T> rhs)
        {   
//这样使用是因为约束
            return data.CompareTo(rhs.data);
        }
        
public bool Equals(Node<T> rhs)
        {
            
return this.data.Equals(rhs.data);
        }
        
//方法
        public Node<T> Add(Node<T> newNode)
        {   
//下面的“我”代表类的当前实例
            if (this.CompareTo(newNode) > 0//小于我则放在我前面
            {
                newNode.next 
= this//新节点的下一节点指向我
                
//如果我有前一个节点,则新节点的前一个节点指向它
                
//新节点做为它的下一个节点
                if (this.prev != null)
                {
                    
this.prev.next = newNode;
                    newNode.prev 
= this.prev;
                }
                
//设置我的前一个节点为新节点
                this.prev = newNode;
                
//从下面的LinkedList<T>代码可以得知,添加都是从
                
//头节点开始判断,只有新节点为头节点时才返回它
                return newNode;
            }
            
else //大于等于我则放在我后面
            {
                
//如果我有下一个,则跟下一个进行对比
                
//这里使用了递归,直到新节点找到比它大的节点为止
                if (this.next != null)
                {
                    
this.next.Add(newNode);
                }
                
//如果我没有下一个节点,则设置新节点为我的下一个
                
//节点,并把它的上一个节点指向我
                else
                {
                    
this.next = newNode;
                    newNode.prev 
= this;
                }
                
return this;
            }
        }
        
public override string ToString()
        {
            
string output = data.ToString();
            
if (next != null)
            {   
//这里也使用了递归打印链表上的所有元素
                output += "" + next.ToString();
            }
            
return output;
        }
    }
    
public class LinkedList<T> where T : IComparable<T>
    {
        
//成员变量
        private Node<T> headNode = null;
        
//索引器
        public T this[int index]
        {
            
get
            {   
//由于是链表,这里需要从头遍历
                int ctr = 0;
                Node
<T> node = headNode;
                
while (node != null && ctr <= index)
                {
                    
if (ctr == index)
                    {
                        
return node.Data;
                    }
                    
else
                    {
                        node 
= node.Next;
                    }
                    
++ctr;
                }
                
throw new ArgumentOutOfRangeException();
            }
        }
        
//默认构造方法
        public LinkedList()
        {
        }
        
//方法
        public void Add(T data)
        {
            
if (headNode == null)
            {
                headNode 
= new Node<T>(data);
            }
            
else
            {
                headNode 
= headNode.Add(new Node<T>(data));
            }
        }
        
public override string ToString()
        {
            
if (this.headNode != null)
            {
                
return this.headNode.ToString();
            }
            
else
            {
                
return string.Empty;
            }
        }
    }
    
//测试类
    class Test
    {
        
static void Main()
        {   
//创建一个实例来进行方法
            Test t = new Test();
            t.Run();
        }
        
public void Run()
        {
            LinkedList
<int> myLinkedList = new LinkedList<int>();
            Random rand 
= new Random();
            Console.Write(
"Adding: ");
            
for (int i = 0; i < 10; i++)
            {
                
int nextInt = rand.Next(10);
                Console.Write(
"{0} ", nextInt);
                myLinkedList.Add(nextInt);
            }

            LinkedList
<Employee> employees = new LinkedList<Employee>();
            employees.Add(
new Employee("John"));
            employees.Add(
new Employee("Paul"));
            employees.Add(
new Employee("George"));
            employees.Add(
new Employee("Ringo"));

            Console.WriteLine(
"\nRetrieving collections");
            Console.WriteLine(
"Integers: " + myLinkedList);
            Console.WriteLine(
"Employees: " + employees);
        }
    }
}

 

运行结果:

Adding2 1 2 6 1 5 9 0 5

Retrieving collections…

Integers0,1,1,1,2,2,5,5,6,9

EmployeesGeorge, John, Paul, Ringo

本例的开头声明了一个可以放到链表中的类:

public class Employee : IComparable<Employee>

这个声明指出Employee对象是可以进行对比的,可以看到Employee类实现了CompareToEquals方法。注意:这些方法是类型安全的(从参数传递进去的类是Employee类型)。LinkedList本身声明为只操作实现了IComparable接口的类型:

public class LinkedList<T> where T : IComparable<T>

这样就可以保证对列表进行排序。LinkedList操作Node类型的对象。Node也实现了IComparable接口,并要求它本身所操作的数据也实现了IComparable接口:

public class Node<T> : IComparable<Node<T>> where T : IComparable<T>

这些约束使得Node实现CompareTo方法变得安全而简单,因为Node知道它将和其它Node的数据进行对比:

public int CompareTo(Node<T> rhs)

{

    // 这样使用是因为约束

    return data.CompareTo(rhs.data);

}

注意,我们不需要测试rhs从而得知它是否实现了IComparable接口;我们已经约束了Node只能操作实现了IComparable接口的数据。
posted @ 2008-02-09 10:44  abatei  阅读(2376)  评论(0编辑  收藏  举报