Vorgehensweise: Hinzufügen von benutzerdefinierten Methoden zu LINQ-Abfragen (C#)

Sie können die Methoden erweitern, die Sie für LINQ-Abfragen durch Hinzufügen von Erweiterungsmethoden zur IEnumerable<T>-Schnittstelle verwenden können. Zusätzlich zu den durchschnittlichen oder maximalen Standardvorgängen, können Sie eine benutzerdefinierte Aggregatmethode erstellen, um einen einzelnen Wert aus einer Sequenz von Werten zu berechnen. Sie können auch eine Methode erstellen, die als benutzerdefinierter Filter oder spezifische Datentransformation für eine Sequenz von Werten agiert und eine neue Sequenz zurückgibt. Beispiele für Methoden dieser Art sind Distinct, Skip und Reverse.

Beim Erweitern der IEnumerable<T>-Schnittstelle können Sie die benutzerdefinierten Methoden auf jede aufzählbare Auflistung anwenden. Weitere Informationen finden Sie unter Erweiterungsmethoden.

Hinzufügen einer Aggregatmethode

Eine aggregierte Methode berechnet einen einzelnen Wert aus einer Gruppe von Werten. LINQ stellt mehrere Aggregatmethoden bereit, einschließlich Average, Min und Max. Sie können Ihre eigene Aggregatmethode erstellen, indem Sie der IEnumerable<T>-Schnittstelle eine Erweiterungsmethode hinzufügen.

Im folgenden Codebeispiel wird veranschaulicht, wie eine Erweiterungsmethode namens Median erstellt wird, um einen Median für eine Zahlensequenz des Typs double zu berechnen.

public static class LINQExtension  
{  
    public static double Median(this IEnumerable<double> source)  
    {  
        if (source.Count() == 0)  
        {  
            throw new InvalidOperationException("Cannot compute median for an empty set.");  
        }  

        var sortedList = from number in source  
                         orderby number  
                         select number;  

        int itemIndex = (int)sortedList.Count() / 2;  

        if (sortedList.Count() % 2 == 0)  
        {  
            // Even number of items.  
            return (sortedList.ElementAt(itemIndex) + sortedList.ElementAt(itemIndex - 1)) / 2;  
        }  
        else  
        {  
            // Odd number of items.  
            return sortedList.ElementAt(itemIndex);  
        }  
    }  
}  

Sie können diese Erweiterungsmethode für jede aufzählbare Auflistung genau so aufrufen, wie Sie andere Aggregatmethoden aus der IEnumerable<T>-Schnittstelle aufrufen.

Im folgenden Codebeispiel wird die Verwendung der Median-Methode für ein Array des Typs double veranschaulicht.

double[] numbers1 = { 1.9, 2, 8, 4, 5.7, 6, 7.2, 0 };  

var query1 = numbers1.Median();  

Console.WriteLine("double: Median = " + query1);  
/*  
 This code produces the following output:  

 Double: Median = 4.85  
*/  

Überladen einer Aggregatmethode zum Akzeptieren verschiedener Typen

Sie können die Aggregatmethode überladen, sodass diese Sequenzen verschiedener Typen akzeptiert. Die Standardmethode ist die Erstellung einer Überladung für jeden Typ. Ein anderer Ansatz ist das Erstellen einer Überladung, die einen generischen Typ annimmt und diesen mit einem Delegaten in einen bestimmten Typ konvertiert. Sie können auch beide Methoden kombinieren.

So erstellen Sie eine Überladung für jeden Typ

Sie können eine bestimmte Überladung für jeden Typ erstellen, den Sie unterstützen möchten. Im folgenden Codebeispiel wird eine Überladung der Median-Methode für den integer-Typ veranschaulicht.

//int overload  

public static double Median(this IEnumerable<int> source)  
{  
    return (from num in source select (double)num).Median();  
}  

Sie können nun die Median-Überladungen für die integer- und double-Typen aufrufen, so wie im folgenden Code gezeigt:

double[] numbers1 = { 1.9, 2, 8, 4, 5.7, 6, 7.2, 0 };  

var query1 = numbers1.Median();  

Console.WriteLine("double: Median = " + query1);  
int[] numbers2 = { 1, 2, 3, 4, 5 };  

var query2 = numbers2.Median();  

Console.WriteLine("int: Median = " + query2);  
/*  
 This code produces the following output:  

 Double: Median = 4.85  
 Integer: Median = 3  
*/  

So erstellen Sie eine generische Überladung

Sie können auch eine Überladung erstellen, die eine Sequenz generischer Objekte akzeptiert. Diese Überladung nimmt einen Delegaten als Parameter und verwendet ihn, um eine Sequenz von Objekten eines generischen Typs in einen bestimmten Typ zu konvertieren.

Der folgende Code zeigt eine Überladung der Median-Methode, die den Func<T,TResult>-Delegaten als Parameter akzeptiert. Dieser Delegat übernimmt ein Objekt des generischen Typs „T“ und gibt ein Objekt vom Typ double zurück.

// Generic overload.  

public static double Median<T>(this IEnumerable<T> numbers,  
                       Func<T, double> selector)  
{  
    return (from num in numbers select selector(num)).Median();  
}  

Sie können nun die Median-Methode für eine Sequenz von Objekten beliebigen Typs aufrufen. Wenn der Typ nicht über eine eigene Methodenüberladung verfügt, müssen sie einen Delegatenparameter übergeben. In C# können Sie zu diesem Zweck einen Lambdaausdruck verwenden. Wenn Sie die Aggregate- oder Group By-Klausel anstatt des Methodenaufrufs verwenden, können Sie auch einen beliebigen Wert oder Ausdruck übergeben, der im Bereich dieser Klausel vorhanden ist. Diese Methode ist nur in Visual Basic verfügbar.

Der folgende Beispielcode veranschaulicht, wie eine Median-Methode für ein Array aus ganzen Zahlen und ein Array aus Zeichenfolgen aufgerufen wird. Für Zeichenfolgen wird der Median für die Längen der Zeichenfolgen im Array berechnet. Das Beispiel zeigt, wie der Delegatparameter Func<T,TResult> an die Median-Methode für jeden Fall übergeben wird.

int[] numbers3 = { 1, 2, 3, 4, 5 };  

/*   
  You can use the num=>num lambda expression as a parameter for the Median method   
  so that the compiler will implicitly convert its value to double.  
  If there is no implicit conversion, the compiler will display an error message.            
*/  

var query3 = numbers3.Median(num => num);  

Console.WriteLine("int: Median = " + query3);  

string[] numbers4 = { "one", "two", "three", "four", "five" };  

// With the generic overload, you can also use numeric properties of objects.  

var query4 = numbers4.Median(str => str.Length);  

Console.WriteLine("String: Median = " + query4);  

/*  
 This code produces the following output:  

 Integer: Median = 3  
 String: Median = 4  
*/  

Hinzufügen einer Methode, die eine Auflistung zurückgibt

Sie können die Schnittstelle IEnumerable<T> mit einer benutzerdefinierten Abfragemethode erweitern, die eine Sequenz von Werten zurückgibt. In diesem Fall muss die Methode eine Auflistung des Typs IEnumerable<T> zurückgeben. Solche Methoden können verwendet werden, um Filter oder Datentransformationen auf eine Sequenz von Werten anzuwenden.

Das folgende Beispiel zeigt, wie eine Erweiterungsmethode mit dem Namen AlternateElements erstellt wird, die jedes andere Element in einer Auflistung zurückgibt, beginnend mit dem ersten Element.

// Extension method for the IEnumerable<T> interface.   
// The method returns every other element of a sequence.  

public static IEnumerable<T> AlternateElements<T>(this IEnumerable<T> source)  
{  
    List<T> list = new List<T>();  

    int i = 0;  

    foreach (var element in source)  
    {  
        if (i % 2 == 0)  
        {  
            list.Add(element);  
        }  

        i++;  
    }  

    return list;  
}  

Sie können diese Erweiterungsmethode für jede aufzählbare Auflistung genau so aufrufen, wie Sie andere Methoden aus der IEnumerable<T>-Schnittstelle aufrufen, so wie im folgenden Code dargestellt:

string[] strings = { "a", "b", "c", "d", "e" };  

var query = strings.AlternateElements();  

foreach (var element in query)  
{  
    Console.WriteLine(element);  
}  
/*  
 This code produces the following output:  

 a  
 c  
 e  
*/  

Siehe auch

IEnumerable<T>
Erweiterungsmethoden