Dies ist nur eine Neugierfrage, auf die ich mich gefragt habe, ob jemand eine gute Antwort auf Folgendes 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, als würde das Predicate<TSource>
nur von List<T>
und verwendet Array<T>
, während Func<TSource, bool>
es von so ziemlich allen Queryable
und Enumerable
Methoden und Erweiterungsmethoden verwendet wird ... was ist damit los?
Antworten:
Während
Predicate
hat zur gleichen Zeit eingeführt worden , dassList<T>
undArray<T>
in .NET 2.0, die verschiedenenFunc
undAction
kommen Varianten von .net 3.5.Daher werden diese
Func
Prädikate hauptsächlich aus Gründen der Konsistenz in den LINQ-Operatoren verwendet. Ab .net 3.5, über die VerwendungFunc<T>
undAction<T>
die Richtlinie besagt :quelle
Ich habe mich das schon einmal gefragt. Ich mag den
Predicate<T>
Delegierten - es ist nett und beschreibend. Sie müssen jedoch die Überlastungen berücksichtigen vonWhere
:Auf diese Weise können Sie auch nach dem Index des Eintrags filtern. Das ist schön und konsequent, während:
wäre nicht.
quelle
Where
Erweiterungsmethode lautetpredicate
. Heh = P.Der eigentliche Grund für die Verwendung
Func
anstelle eines bestimmten Delegaten ist sicherlich, dass C # separat deklarierte Delegaten als völlig unterschiedliche Typen behandelt.Obwohl
Func<int, bool>
undPredicate<int>
beide identische Argumente und Rückgabetypen haben, sind sie nicht zuweisungskompatibel. Wenn also jede Bibliothek ihren eigenen Delegatentyp für jedes Delegatenmuster deklariert, können diese Bibliotheken nur dann zusammenarbeiten, wenn der Benutzer "Bridging" -Delegierte einfügt, um Konvertierungen durchzuführen.Durch die Ermutigung aller zur Verwendung von Func hofft Microsoft, dass dies das Problem inkompatibler Delegatentypen lindert. Alle Delegierten werden gut zusammenspielen, da sie nur anhand ihrer Parameter- / Rückgabetypen abgeglichen werden.
Es werden nicht alle Probleme zu lösen, weil
Func
(undAction
) nicht habenout
oderref
Parameter, aber die sind weniger häufig verwendet.Update: In den Kommentaren sagt Svish:
Ja, solange Ihr Programm nur Delegaten Methoden zuweist, wie in der ersten Zeile meiner
Main
Funktion. Der Compiler generiert stillschweigend Code für ein neues Delegatenobjekt, das an die Methode weitergeleitet wird. In meinerMain
Funktion konnte ichx1
alsoExceptionHandler2
ohne Probleme vom Typ wechseln .In der zweiten Zeile versuche ich jedoch, den ersten Delegierten einem anderen Delegierten zuzuweisen. Obwohl der 2. Delegattyp genau den gleichen Parameter- und Rückgabetyp hat, gibt der Compiler einen Fehler aus
CS0029: Cannot implicitly convert type 'ExceptionHandler1' to 'ExceptionHandler2'
.Vielleicht wird dies klarer:
Meine Methode
IsNegative
ist eine sehr gute Sache, um die Variablenp
und zuzuweisenf
, solange ich dies direkt tue. Aber dann kann ich keine dieser Variablen der anderen zuweisen.quelle
Func<T, bool>
oderPredicate<T>
nicht als vom Compiler abgeleiteter Typ eingegeben wird .Der Rat (in 3.5 und höher) ist, das
Action<...>
undFunc<...>
- für das "Warum?" - Ein Vorteil ist, dass "Predicate<T>
" nur dann sinnvoll ist, wenn Sie wissen, was "Prädikat" bedeutet. Andernfalls müssen Sie sich den Objektbrowser (usw.) ansehen, um den Signatute zu finden.Umgekehrt
Func<T,bool>
folgt ein Standardmuster; Ich kann sofort erkennen, dass dies eine Funktion ist, die a annimmtT
und a zurückgibtbool
- ich muss keine Terminologie verstehen - einfach meinen Wahrheitstest anwenden.Für "Prädikat" mag dies in Ordnung gewesen sein, aber ich schätze den Versuch der Standardisierung. Es erlaubt auch viel Parität mit den verwandten Methoden in diesem Bereich.
quelle