泛型接口(C# 编程指南)Generic Interfaces (C# Programming Guide)

为泛型集合类或表示集合中的项的泛型类定义接口通常很有用处。It is often useful to define interfaces either for generic collection classes, or for the generic classes that represent items in the collection. 为避免对值类型的装箱和取消装箱操作,泛型类的首选项使用泛型接口,例如 IComparable<T>而不是 IComparableThe preference for generic classes is to use generic interfaces, such as IComparable<T> rather than IComparable, in order to avoid boxing and unboxing operations on value types. .NET Framework 类库定义多个泛型接口,以将其用于 System.Collections.Generic 命名空间中的集合类。The .NET Framework class library defines several generic interfaces for use with the collection classes in the System.Collections.Generic namespace.

接口被指定为类型参数上的约束时,仅可使用实现接口的类型。When an interface is specified as a constraint on a type parameter, only types that implement the interface can be used. 如下代码示例演示一个派生自 GenericList<T> 类的 SortedList<T> 类。The following code example shows a SortedList<T> class that derives from the GenericList<T> class. 有关详细信息,请参阅泛型介绍For more information, see Introduction to Generics. SortedList<T> 添加约束 where T : IComparable<T>SortedList<T> adds the constraint where T : IComparable<T>. 这可使 SortedList<T> 中的 BubbleSort 方法在列表元素上使用泛型 CompareTo 方法。This enables the BubbleSort method in SortedList<T> to use the generic CompareTo method on list elements. 在此示例中,列表元素是一个实现 IComparable<Person> 的简单类 PersonIn this example, list elements are a simple class, Person, that implements IComparable<Person>.

//Type parameter T in angle brackets.
public class GenericList<T> : System.Collections.Generic.IEnumerable<T>
{
    protected Node head;
    protected Node current = null;

    // Nested class is also generic on T
    protected class Node
    {
        public Node next;
        private T data;  //T as private member datatype

        public Node(T t)  //T used in non-generic constructor
        {
            next = null;
            data = t;
        }

        public Node Next
        {
            get { return next; }
            set { next = value; }
        }

        public T Data  //T as return type of property
        {
            get { return data; }
            set { data = value; }
        }
    }

    public GenericList()  //constructor
    {
        head = null;
    }

    public void AddHead(T t)  //T as method parameter type
    {
        Node n = new Node(t);
        n.Next = head;
        head = n;
    }

    // Implementation of the iterator
    public System.Collections.Generic.IEnumerator<T> GetEnumerator()
    {
        Node current = head;
        while (current != null)
        {
            yield return current.Data;
            current = current.Next;
        }
    }

    // IEnumerable<T> inherits from IEnumerable, therefore this class 
    // must implement both the generic and non-generic versions of 
    // GetEnumerator. In most cases, the non-generic method can 
    // simply call the generic method.
    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

public class SortedList<T> : GenericList<T> where T : System.IComparable<T>
{
    // A simple, unoptimized sort algorithm that 
    // orders list elements from lowest to highest:

    public void BubbleSort()
    {
        if (null == head || null == head.Next)
        {
            return;
        }
        bool swapped;

        do
        {
            Node previous = null;
            Node current = head;
            swapped = false;

            while (current.next != null)
            {
                //  Because we need to call this method, the SortedList
                //  class is constrained on IEnumerable<T>
                if (current.Data.CompareTo(current.next.Data) > 0)
                {
                    Node tmp = current.next;
                    current.next = current.next.next;
                    tmp.next = current;

                    if (previous == null)
                    {
                        head = tmp;
                    }
                    else
                    {
                        previous.next = tmp;
                    }
                    previous = tmp;
                    swapped = true;
                }
                else
                {
                    previous = current;
                    current = current.next;
                }
            }
        } while (swapped);
    }
}

// A simple class that implements IComparable<T> using itself as the 
// type argument. This is a common design pattern in objects that 
// are stored in generic lists.
public class Person : System.IComparable<Person>
{
    string name;
    int age;

    public Person(string s, int i)
    {
        name = s;
        age = i;
    }

    // This will cause list elements to be sorted on age values.
    public int CompareTo(Person p)
    {
        return age - p.age;
    }

    public override string ToString()
    {
        return name + ":" + age;
    }

    // Must implement Equals.
    public bool Equals(Person p)
    {
        return (this.age == p.age);
    }
}

class Program
{
    static void Main()
    {
        //Declare and instantiate a new generic SortedList class.
        //Person is the type argument.
        SortedList<Person> list = new SortedList<Person>();

        //Create name and age values to initialize Person objects.
        string[] names = new string[] 
        { 
            "Franscoise", 
            "Bill", 
            "Li", 
            "Sandra", 
            "Gunnar", 
            "Alok", 
            "Hiroyuki", 
            "Maria", 
            "Alessandro", 
            "Raul" 
        };

        int[] ages = new int[] { 45, 19, 28, 23, 18, 9, 108, 72, 30, 35 };

        //Populate the list.
        for (int x = 0; x < 10; x++)
        {
            list.AddHead(new Person(names[x], ages[x]));
        }

        //Print out unsorted list.
        foreach (Person p in list)
        {
            System.Console.WriteLine(p.ToString());
        }
        System.Console.WriteLine("Done with unsorted list");

        //Sort the list.
        list.BubbleSort();

        //Print out sorted list.
        foreach (Person p in list)
        {
            System.Console.WriteLine(p.ToString());
        }
        System.Console.WriteLine("Done with sorted list");
    }
}

可将多个接口指定为单个类型上的约束,如下所示:Multiple interfaces can be specified as constraints on a single type, as follows:

class Stack<T> where T : System.IComparable<T>, IEnumerable<T>
{
}

一个接口可定义多个类型参数,如下所示:An interface can define more than one type parameter, as follows:

interface IDictionary<K, V>
{
}

适用于类的继承规则也适用于接口:The rules of inheritance that apply to classes also apply to interfaces:

interface IMonth<T> { }

interface IJanuary     : IMonth<int> { }  //No error
interface IFebruary<T> : IMonth<int> { }  //No error
interface IMarch<T>    : IMonth<T> { }    //No error
//interface IApril<T>  : IMonth<T, U> {}  //Error

泛型接口如为逆变(即,仅使用自身的类型参数作为返回值),则可继承自非泛型接口。Generic interfaces can inherit from non-generic interfaces if the generic interface is contravariant, which means it only uses its type parameter as a return value. 在 .NET Framework 类库中,IEnumerable<T> 继承自 IEnumerable,因为 IEnumerable<T>GetEnumerator 的返回值和 Current 属性 Getter 中仅使用 TIn the .NET Framework class library, IEnumerable<T> inherits from IEnumerable because IEnumerable<T> only uses T in the return value of GetEnumerator and in the Current property getter.

具体类可实现封闭式构造接口,如下所示:Concrete classes can implement closed constructed interfaces, as follows:

interface IBaseInterface<T> { }

class SampleClass : IBaseInterface<string> { }

只要类形参列表提供接口所需的所有实参,泛型类即可实现泛型接口或封闭式构造接口,如下所示:Generic classes can implement generic interfaces or closed constructed interfaces as long as the class parameter list supplies all arguments required by the interface, as follows:

interface IBaseInterface1<T> { }
interface IBaseInterface2<T, U> { }

class SampleClass1<T> : IBaseInterface1<T> { }          //No error
class SampleClass2<T> : IBaseInterface2<T, string> { }  //No error

控制方法重载的规则对泛型类、泛型结构或泛型接口内的方法一样。The rules that control method overloading are the same for methods within generic classes, generic structs, or generic interfaces. 有关详细信息,请参阅泛型方法For more information, see Generic Methods.

请参阅See also