Frage

Das ist nur eine Kuriosität Frage, die ich frage mich, ob jemand eine gute Antwort auf hatte:

In der .NET Framework-Klassenbibliothek haben wir zum Beispiel diese beiden Methoden:

public static IQueryable<TSource> Where<TSource>(
    this IQueryable<TSource> source,
    Expression<Func<TSource, bool>> predicate
)

public static IEnumerable<TSource> Where<TSource>(
    this IEnumerable<TSource> source,
    Func<TSource, bool> predicate
)

Warum verwenden sie Func<TSource, bool> statt Predicate<TSource>? Scheint, wie die Predicate<TSource> nur durch List<T> und Array<T> verwendet wird, während Func<TSource, bool> durch so ziemlich alle Queryable und Enumerable Methoden und Erweiterungsmethoden verwendet wird ... was damit los ist?

War es hilfreich?

Lösung

Während Predicate hat zur gleichen Zeit eingeführt worden, die List<T> und Array<T>, in .net 2.0, die verschiedenen Func und Action Varianten kommen aus .net 3.5.

So jene Func Prädikate verwendet werden, vor allem für die Konsistenz in den LINQ-Operatoren. Ab .net 3.5, über Func<T> mit und Action<T> die Richtlinie Staaten :

  

Sie die neue LINQ Arten Func<> verwenden und   Expression<> statt benutzerdefinierten   Delegierten und Prädikate

Andere Tipps

Ich habe dies vor sich. Ich mag die Predicate<T> Delegierten - es ist schön und beschreibend. Allerdings müssen Sie die Überlastung von Where berücksichtigen:

Where<T>(IEnumerable<T>, Func<T, bool>)
Where<T>(IEnumerable<T>, Func<T, int, bool>)

Das erlaubt Ihnen auch auf dem Index des Eintrags zu filtern. Das ist schön und konsequent, während:

Where<T>(IEnumerable<T>, Predicate<T>)
Where<T>(IEnumerable<T>, Func<T, int, bool>)

wäre nicht.

Denn der eigentliche Grund für Func anstelle eines bestimmten Delegierten ist, dass C # behandelt als völlig unterschiedliche Arten getrennt Delegierten erklärt.

Auch wenn Func<int, bool> und beide Predicate<int> identisch Argument haben und Rückgabetypen, sie sind nicht zuweisungskompatibel. Also, wenn jede Bibliothek einen eigenen Delegattyp für jeden Delegierten Muster erklärt, würden diese Bibliotheken nicht in der Lage sein, zu interagieren, wenn der Benutzer Einsätze „Überbrückung“ Delegierten Umwandlungen durchzuführen.

    // declare two delegate types, completely identical but different names:
    public delegate void ExceptionHandler1(Exception x);
    public delegate void ExceptionHandler2(Exception x);

    // a method that is compatible with either of them:
    public static void MyExceptionHandler(Exception x)
    {
        Console.WriteLine(x.Message);
    }

    static void Main(string[] args)
    {
        // can assign any method having the right pattern
        ExceptionHandler1 x1 = MyExceptionHandler; 

        // and yet cannot assign a delegate with identical declaration!
        ExceptionHandler2 x2 = x1; // error at compile time
    }

Mit jeder Förderung Func zu verwenden, Microsoft hofft, dass dies das Problem inkompatibler Delegattypen wird lindern. Jeder Teilnehmer wird gut zusammen spielen, weil sie nur nach oben angepasst werden auf der Grundlage ihrer Parameter / Rückgabetypen.

Es löst nicht alle Probleme, weil Func (und Action) nicht out oder ref Parameter haben, aber die sind weniger häufig verwendet.

Update: in den Kommentaren Svish sagt:

  

Dennoch Schalten eines Parametertyp aus   Func auszusagen und   zurück, scheint nicht zu machen   Unterschied? Zumindest kompiliert es noch   ohne Probleme.

Ja, solange Ihr Programm nur Methoden an den Delegierten zuweist, wie in der ersten Zeile meiner Main Funktion. Der Compiler erzeugt geräuschlos Code zu neuen einem Delegatobjekt, die auf das Verfahren leitet auf. Also in meiner Main Funktion, kann ich x1 ändern Typ ExceptionHandler2 sein, ohne ein Problem zu verursachen.

Doch in der zweiten Zeile ich versuche, den ersten Delegierten zu einem anderen Delegierten zuweisen. Selbst angenommen, dass die 2. Delegattyp genau den gleichen Parameter hat und Rückgabetypen, der Compiler gibt Fehler CS0029: Cannot implicitly convert type 'ExceptionHandler1' to 'ExceptionHandler2'.

Vielleicht wird es deutlicher:

public static bool IsNegative(int x)
{
    return x < 0;
}

static void Main(string[] args)
{
    Predicate<int> p = IsNegative;
    Func<int, bool> f = IsNegative;

    p = f; // Not allowed
}

Meine Methode IsNegative ist eine ganz gute Sache auf die p und f Variablen zugewiesen werden, solange es so direkt zu tun. Aber dann kann ich nicht zuordnen eine dieser Variablen auf der anderen Seite.

Der Rat (in 3.5 und höher) ist die Action<...> und Func<...> zu verwenden - „Warum?“ Für die - ein Vorteil ist, dass „Predicate<T>“ nur dann sinnvoll ist, wenn Sie wissen, was „Prädikat“ bedeutet -. Andernfalls müssen Sie bei Objekt-Browser aussehen (usw.), um die signatute zu finden

Im Gegensatz Func<T,bool> folgt ein Standardmuster; Ich kann sofort sagen, dass dies eine Funktion, die eine T nimmt und gibt ein bool - brauchen keine Terminologie zu verstehen -. Nur meine Wahrheit Test anwenden

„Prädikat“ dies OK gewesen sein könnte, aber ich schätze den Versuch zu standardisieren. Es ermöglicht auch eine Menge Parität mit den entsprechenden Methoden in diesem Bereich.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top