Wie erstelle ich eine generische Erweiterungsmethode?

73

Ich möchte eine generische Erweiterungsmethode entwickeln, die die Zeichenfolge in alphabetischer Reihenfolge und dann in aufsteigender Reihenfolge in Längsrichtung anordnet.

ich meine

string[] names = { "Jon", "Marc", "Joel",
                  "Thomas", "Copsey","Konrad","Andrew","Brian","Bill"};

var query = names.OrderBy(a => a.Length).ThenBy(a => a);

Wie kann die generische Erweiterungsmethode entwickelt werden?

Ich habe es versucht :

public static class ExtensionOperation
    {
        public static T[] AlphaLengthWise<T>(this T[] names)
        {
            var query = names.OrderBy(a => a.Length).ThenBy(a => a);
            return query;
        }
    }

Ich erhielt :

Fehler 1: T enthält keine Definition für Länge

Fehler 2: Konvertiert nicht System.Linq.IOrderedEnumerablein T[].

user215675
quelle
3
Eine generische Methode zu haben, die nur mit Strings funktioniert, macht nicht wirklich viel Sinn ...
Jason Punyon
4
Warum sollte es generisch sein, wenn Sie nur Zeichenfolgen anordnen möchten?
bniwredyc
6
@bniwredyc Weil es genericcool klingt! :)
Arnis Lapsa
Sie können auch richtig wollen ExtensionOperstionzuExtensionOperation
Alex Bagnolini

Antworten:

105

Der erste Fehler liegt darin, dass Lengthes sich um eine Eigenschaft der StringKlasse handelt, während in Ihrer generischen Version der Typ des T-Parameters nicht bekannt ist. Es könnte jeder Typ sein.

Der zweite Fehler liegt darin, dass Sie nur das Abfrageobjekt zurückgeben, nicht jedoch das tatsächliche Ergebnis. Möglicherweise müssen Sie anrufen, ToArray()bevor Sie zurückkehren.

Mit kleinen Änderungen könnten Sie sich Folgendes einfallen lassen:

public static class ExtensionOperation
{
    public static IEnumerable<T> AlphaLengthWise<T, L>(
        this IEnumerable<T> names, Func<T, L> lengthProvider)
    {
        return names
            .OrderBy(a => lengthProvider(a))
            .ThenBy(a => a);
    }
}

Was Sie so verwenden könnten:

string[] names = { "Jon", "Marc", "Joel", "Thomas", "Copsey", "Konrad", "Andrew", "Brian", "Bill" };
var result = names.AlphaLengthWise(a => a.Length);
Darin Dimitrov
quelle
1
Ich finde mich dabei, solche Techniken häufig lengthProvidermit generischem Code zu verwenden. Es ist nur ein Grund mehr, warum ich Lambdas so sehr liebe. : D
Greg D
14

Warum möchten Sie dies generisch tun? Benutz einfach

public static class ExtensionOperations
{
    public static IEnumerable<string> AlphaLengthWise(this string[] names)
    {
        var query = names.OrderBy(a => a.Length).ThenBy(a => a);
        return query;
    }
}
Maximilian Mayerl
quelle
4
Warum string[]und nicht IEnumerable<String>? Sie können das entfernen .ToArray()und aufgeschoben lassen (wenn ich mich nicht irre).
Alex Bagnolini
1
Dies ignoriert die Frage und bietet eine Lösung für ein völlig anderes Problem
John Smith
7

Ich denke, Sie sind vielleicht ein wenig verwirrt über den Zweck von Generika.

Generika sind eine Möglichkeit, eine Klasse oder Methode an einen bestimmten Typ anzupassen. Eine generische Methode oder Klasse kann für jeden Typ verwendet werden. Dies lässt sich am einfachsten in der List<T>Klasse veranschaulichen, in der eine Liste eines beliebigen Typs erstellt werden kann. Dies gibt Ihnen die Typensicherheit, wenn Sie wissen, dass die Liste nur diesen bestimmten Typ enthält.

Ihr Problem ist darauf ausgelegt, an einem bestimmten Typ, dem stringTyp, zu arbeiten. Generika werden ein Problem, das einen bestimmten Typ betrifft, nicht lösen.

Was Sie wollen, ist eine einfache (nicht generische) Erweiterungsmethode:

public static class ExtensionOperations
{
    public static IEnumerable<string> AlphaLengthWise(
        this IEnumerable<string> names)
    {
        if(names == null)
            throw new ArgumentNullException("names");

        return names.OrderBy(a => a.Length).ThenBy(a => a);
    }
}

Wenn Sie das Argument und den Rückgabetyp festlegen, IEnumerable<string>wird dies zu einer nicht generischen Erweiterungsmethode, die für jeden implementierten Typ gelten kann IEnumerable<string>. Dazu gehört string[], List<string>, ICollection<string>, IQueryable<string>und viele mehr.

Paul Turner
quelle
2

Ich möchte eine generische Erweiterungsmethode entwickeln, die die Zeichenfolgen dann alphabetisch anordnet ...

public static class ExtensionOperation
{
    public static IEnumerable<String> AplhaLengthWise(
                                   this IEnumerable<String> names)
    {
        return names.OrderBy(a => a.Length).ThenBy(a => a);
    }
}
Alex Bagnolini
quelle
1

Kopieren Sie, wie Microsoft es macht:

public static class ExtensionOperation {
    // Handles anything queryable.
    public static IOrderedQueryable<string> AlphaLengthWise(this IQueryable<string> names) {
        return names.OrderBy(a => a.Length).ThenBy(a => a);
    }
    // Fallback method for non-queryable collections.
    public static IOrderedEnumerable<string> AlphaLengthWise(this IEnumerable<string> names) {
        return names.OrderBy(a => a.Length).ThenBy(a => a);
    }
}
Christian Hayter
quelle
0

Sie möchten IEnumerable<T>anstelle von verwenden T[]. Abgesehen davon, werden Sie nicht in der Lage sein zu verwenden , Lengthder T, da nicht alle Typen eine hat LengthEigenschaft. Sie können Ihre Erweiterungsmethode auf ändern.OrderBy(a => a.ToString().Length)

Wenn Sie wissen, dass Sie immer mit Zeichenfolgen zu tun haben, verwenden Sie IEnumerable<String>anstatt IEnumerable<T>, und Sie können Lengthsofort auf die Eigenschaft zugreifen .

David Hedlund
quelle
Das Ändern von T [] in IEnumerable <T> erfordert keine Length-Eigenschaft für Elemente.
Arnis Lapsa
das wird es sicher nicht. Dieser Teil der Antwort bezog sich auf den zweiten Fehler. IOrderedEnumerable<T>implementiert IEnumerable<T>, so dass dieser Teil des Problems lösen würde. Wie für die LengthEigenschaft, war mein Vorschlag , dass ToString()verwendet wurde , um eine Zeichenfolge zu gewährleisten, oder, wenn er neu er immer mit Streichern tun würde, Änderungen Tzu string.
David Hedlund