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>
und Predicate<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.
// 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
}
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
(und Action
) nicht haben out
oder ref
Parameter, aber die sind weniger häufig verwendet.
Update: In den Kommentaren sagt Svish:
Das Umschalten eines Parametertyps von Func auf Predicate und zurück scheint jedoch keinen Unterschied zu machen. Zumindest kompiliert es noch ohne Probleme.
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 meiner Main
Funktion konnte ich x1
also ExceptionHandler2
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:
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 sehr gute Sache, um die Variablen p
und zuzuweisen f
, solange ich dies direkt tue. Aber dann kann ich keine dieser Variablen der anderen zuweisen.