泛型--约束

9.5 约束

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

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

这句代码定义了一个泛型Node,它操作类型T。Node中的T实现了IComparable<T>接口,这意味着两个Node的T可以进行对比。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);
    }
  }
}

时间: 2024-12-03 06:59:24

泛型--约束的相关文章

C# where泛型约束

        最近无意中看到了:http://msdn.microsoft.com/zh-cn/library/bb384067.aspx.但是,人笨啊,木有看懂到底是啥意思,木办法自己写一个试试吧,权当做个笔记 例子如下: 接口: using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace WhereTest { /// <summary> /// 水果接口

asp.net C#中的where泛型约束中的new()

new()解释说到是where字句的构造函数约束,带有new()约束的任何类型都必须有可访问的无参构造函数,正常来说C#创建的类默认都有一个无参的构造函数,即使你没有写,但是如果你写了一个有参数的构造函数后,那么就没有默认无参的那个了,就需要自己手动写一个  代码如下 复制代码 /// <summary> /// 国籍的接口 /// </summary> public interface INationality {     string Nationality     {    

C#泛型有什么好处

关于object类型:1.object类型可以来引用任何类型的实例:2.object类型可以存储任何类型的值:3.可以定义object类型的参数:4.可以把object作为返回类型.但是--这样做有很大的问题 1.会因为程序员没有记住使用的类型而出错,造成类型不兼容:2.值类型和引用类型的互化即装箱拆箱使系统性能下降. C#2.0提出的泛型就是避免强制类型转换,减少装箱拆箱提高性能,减少错误. System.Collections.Generic命名空间提供许多集合类和接口的泛型版本. 定义:p

C++泛型用法

 我们先来看一个最为常见的泛型类型List<T>的定义 (真正的定义比这个要复杂的多,我这里删掉了很多东西) [Serializable]   public class List<T> : IList<T>, ICollection<T>, IEnumerable<T>   {       public T this[int index] { get; set; }       public void Add(T item);       pub

Swift泛型和泛型函数

泛型(generic)可以使我们在程序代码中定义一些可变的部分,在运行的时候指定.使用泛型可以最大限度地重用代码.保护类型的安全以及提高性能.在Swift集合类中,已经采用了泛型.一.一个问题的思考怎样定义一个函数来判断两个参数是否相等呢?如果参数是Int类型,则函数定义如下:func isEqualsInt(a:Int, b:Int) -> Bool {    return (a == b)}这个函数参数列表是两个Int类型,它只能比较两个Int类型参数是否相等.如果我们想比较两个Double

反编译-子类调用父类的泛型方法,为何不用强转就能得到正确的类型,父类编译的时候不是泛型擦出了吗?

问题描述 子类调用父类的泛型方法,为何不用强转就能得到正确的类型,父类编译的时候不是泛型擦出了吗? 以下面这个简单例子演示: 这是父类 public abstract class GenericFather<T> { public T getT(T t){ return t; } } 通过反编译可以得知编译后泛型擦出,T都用Object代替了 也就是说只要调用父类方法最后肯定返回的是个Object类型 public abstract class GenericFather { public G

.net 泛型 局部类型、属性访问器保护级别、命名空间别名限定符

.net 泛型 局部类型.属性访问器保护级别.命名空间别名限定符 泛型1>=局部类型: c#1.0中,一个类只可以放在一个文件中.c#2.0中用了一个关键字<partial>把一个类分成两个部分<即一个类的实现可以在多个文件中>.编译结果和写在一个文件中完全相同,更多的意义在于工程化的管理. ..1>>局部类型值适用与接口.类或者结构中,不支持枚举<一般也没这么大的枚举吧>: ..2>>同一个类型的各个部分必须都有修饰符partial,必须

C#基础之泛型_C#教程

1.泛型的本质 泛型的好处不用多说,在.NET中我看到有很多技术都是以泛型为基础的,不过因为不懂泛型而只能对那些技术一脸茫然.泛型主要用于集合类,最主要的原因是它不需要装箱拆箱且类型安全,比如很常用的List<T>.对于List<T>我以后还想进行深究,现在我写了一个超简版的MyList<T>集合,如下面第一段代码所示.代码很简单,但在写的过程中有一个细节,如果我为listInt赋值string类型的变量时编译器会提示报错.编译器很智能,但是从这个现象中你会不会好奇泛型

泛型继承中,如何在子类中直接访问泛型类中的数据

问题描述 假设我创建了一个类A,并假设类A中定义了许多属性和函数publicclassA{publicintproperty1{get;set;}publicfloatproperty2{get;set;}publicboolproperty3{get;set;}......}假设有一个泛型基类:GenericBase<T>publicclassGenericBase<T>whereT:A{}然后我创建一个新类GenericA继承上面的泛型类publicclassGenericA: