Det är ofta användbart att definiera gränssnitt antingen för generiska samlingsklasser eller för de generiska klasser som representerar objekt i samlingen. För att undvika boxnings- och avboxningsåtgärder för värdetyper är det bättre att använda generiska gränssnitt, till exempel IComparable<T>, i allmänna klasser. .NET-klassbiblioteket definierar flera allmänna gränssnitt för användning med samlingsklasserna i System.Collections.Generic namnområdet. Mer information om dessa gränssnitt finns i Allmänna gränssnitt.
När ett gränssnitt anges som en begränsning för en typparameter kan endast typer som implementerar gränssnittet användas. I följande kodexempel visas en SortedList<T> klass som härleds från GenericList<T> klassen. Mer information finns i Introduktion till generiska objekt. SortedList<T> lägger till villkoret where T : IComparable<T>. Med den här begränsningen BubbleSort kan metoden i SortedList<T> använda den generiska CompareTo metoden för listelement. I det här exemplet är listelement en enkel klass som Person implementerar IComparable<Person>.
C#
//Type parameter T in angle brackets.publicclassGenericList<T> : System.Collections.Generic.IEnumerable<T>
{
protected Node head;
protected Node current = null;
// Nested class is also generic on TprotectedclassNode
{
public Node next;
private T data; //T as private member datatypepublicNode(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; }
}
}
publicGenericList() //constructor
{
head = null;
}
publicvoidAddHead(T t) //T as method parameter type
{
Node n = new Node(t);
n.Next = head;
head = n;
}
// Implementation of the iteratorpublic System.Collections.Generic.IEnumerator<T> GetEnumerator()
{
Node current = head;
while (current != null)
{
yieldreturn 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();
}
}
publicclassSortedList<T> : GenericList<T> whereT : System.IComparable<T>
{
// A simple, unoptimized sort algorithm that// orders list elements from lowest to highest:publicvoidBubbleSort()
{
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.publicclassPerson : System.IComparable<Person>
{
string name;
int age;
publicPerson(string s, int i)
{
name = s;
age = i;
}
// This will cause list elements to be sorted on age values.publicintCompareTo(Person p)
{
return age - p.age;
}
publicoverridestringToString()
{
return name + ":" + age;
}
// Must implement Equals.publicboolEquals(Person p)
{
return (this.age == p.age);
}
}
publicclassProgram
{
publicstaticvoidMain()
{
//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");
}
}
Flera gränssnitt kan anges som begränsningar för en enda typ, enligt följande:
Generiska gränssnitt kan ärva från icke-generiska gränssnitt om det generiska gränssnittet är covariant, vilket innebär att det bara använder sin typparameter som ett returvärde. I .NET-klassbiblioteket IEnumerable<T> ärver du från IEnumerable eftersom IEnumerable<T> endast använder T i returvärdet GetEnumerator för och i Current egenskaps getter.
Betongklasser kan implementera stängda konstruerade gränssnitt på följande sätt:
Generiska klasser kan implementera generiska gränssnitt eller stängda konstruerade gränssnitt så länge klassparameterlistan innehåller alla argument som krävs av gränssnittet, enligt följande:
Reglerna som styr överlagring av metoder är desamma för metoder inom generiska klasser, generiska structs eller generiska gränssnitt. Mer information finns i Allmänna metoder.
Från och med C# 11 kan gränssnitt deklarera static abstract eller static virtual medlemmar. Gränssnitt som deklarerar antingen static abstract eller static virtual medlemmar är nästan alltid allmänna gränssnitt. Kompilatorn måste matcha anrop till static virtual och static abstract metoder vid kompileringstillfället. static virtual och static abstract metoder som deklareras i gränssnitt har inte någon körningssändningsmekanism som motsvarar virtual eller abstract metoder som deklarerats i klasser. Kompilatorn använder i stället typinformation som är tillgänglig vid kompileringstillfället. Dessa medlemmar deklareras vanligtvis i allmänna gränssnitt. Dessutom deklarerar de flesta gränssnitt som deklarerar static virtual eller static abstract metoder att en av typparametrarna måste implementera det deklarerade gränssnittet. Kompilatorn använder sedan de angivna typargumenten för att matcha den deklarerade medlemmens typ.
Källan för det här innehållet finns på GitHub, där du även kan skapa och granska ärenden och pull-begäranden. Se vår deltagarguide för mer information.
Feedback om .NET
.NET är ett öppen källkod projekt. Välj en länk för att ge feedback:
Lär dig mer om generiska läkemedel. Allmänna typer maximerar återanvändning av kod, typsäkerhet och prestanda och används ofta för att skapa samlingsklasser.