泛型介面 (C# 程式設計手冊)

定義表示集合中項目的泛型集合類別或泛型類別的介面,通常很有用。 為了避免實值型別的 Boxing 和 unboxing 作業,最好在泛型類別上使用泛型介面,例如 IComparable<T>。 .NET 類別庫定義數個泛型介面,以供搭配 System.Collections.Generic 命名空間中的集合類別使用。 如需這些介面的詳細資訊,請參閱泛型介面

將介面指定為型別參數的條件約束時,只能使用使用實作介面的類型。 下列程式碼範例示範衍生自 GenericList<T> 類別的 SortedList<T> 類別。 如需詳細資訊,請參閱泛型簡介SortedList<T> 會新增條件約束 where T : IComparable<T>。 此限制式可讓 SortedList<T>BubbleSort 方法使用 List 元素上的泛型 CompareTo 方法。 在此範例中,List 元素是簡單的類別 Person,它會實作 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 IComparable<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);
    }
}

public class Program
{
    public 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 =
        [
            "Franscoise",
            "Bill",
            "Li",
            "Sandra",
            "Gunnar",
            "Alok",
            "Hiroyuki",
            "Maria",
            "Alessandro",
            "Raul"
        ];

        int[] ages = [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");
    }
}

多個介面可以指定為單一類型上的條件約束,如下所示:

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

介面可以定義多個型別參數,如下所示:

interface IDictionary<K, V>
{
}

適用於類別的繼承規則也適用於介面:

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

如果泛型介面是 covariant,泛型介面就可以繼承自非泛型介面,這表示該介面只會使用自己的型別參數當作傳回值。 在 .NET 類別庫中,IEnumerable<T> 繼承自 IEnumerable,因為在 GetEnumerator 的傳回值和 Current 屬性 getter 中,IEnumerable<T> 只會使用 T

實體類別可以實作封閉式建構介面,如下所示:

interface IBaseInterface<T> { }

class SampleClass : IBaseInterface<string> { }

泛型類別可以實作泛型介面或封閉式建構介面,只要類別參數清單提供介面需要的所有引數,如下所示:

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

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

控制方法多載的規則,和用於泛型類別、泛型結構或泛型介面中的方法的規則一樣。 如需詳細資訊,請參閱泛型方法

從 C# 11 開始,介面可以宣告 static abstractstatic virtual 成員。 宣告 static abstractstatic virtual 成員的介面幾乎一律是泛型介面。 編譯器必須在編譯時間解析呼叫 static virtualstatic abstract 方法。 介面中宣告的 static virtualstatic abstract 方法沒有類似類別中宣告的 virtualabstract 執行時間分派機制。 而編譯器會使用編譯時間可用的型別資訊。 這些成員通常會在泛型介面中宣告。 此外,大多數宣告 static virtualstatic abstract 方法的介面都會宣告其中一個型別參數必須實作宣告的介面。 編譯器接著會使用提供的型別引數解析宣告成員的類型。

另請參閱