Warum ist diese Besetzung überflüssig?

73

Ich habe eine Methode mit folgenden Überladungen:

string Call(string function, Dictionary<string, object> parameters, object body)
string Call(string function, Dictionary<string, object> parameters, JObject body)

Jetzt habe ich eine weitere Überladung hinzugefügt:

string Call(string function)
{
    return Call(function, null, (JObject) null);
}

Ich habe eine Besetzung hinzugefügt, JObjectdamit der Compiler weiß, welche Überladung er verwenden soll. Aber Visual Studio sagt mir, dass die Besetzung redundant ist. Aber warum ist mein Anruf ohne die Besetzung nicht mehrdeutig?

Fero
quelle
19
Selbst wenn es für den Compiler nicht mehrdeutig ist, würde ich die Besetzung dort behalten, da es für die Person, die den Code liest, mehrdeutig sein könnte
Alex
5
@ Jean Nein, das ist nicht der Grund. Ich sage dem Compiler, welche Überladung verwendet werden soll. Und es spielt keine Rolle, welche Methodenüberladung verwendet wird, da sie völlig unterschiedliche Implementierungen haben könnten. nullist null, aber die Besetzung hier ist ein Hinweis, welche Überladung verwendet werden sollte.
Fero
1
@ Jean Ich fürchte, das ist wieder falsch. Die Besetzung ist nur überflüssig , weil der Compiler noch die Verwendung JObjectÜberlastung , auch wenn ich zu werfen nicht , JObjectweil es die meisten spezifische Überlastung verwendet, die die Parameter übereinstimmt, und nullalles bieten kann und JObject ist spezifischer als object. Eine ausführliche Erklärung finden Sie in der Antwort von Jon Skeet.
Fero

Antworten:

98

Aber warum ist mein Anruf ohne die Besetzung nicht mehrdeutig?

Weil die Überladung mit dem JObjectParameter "besser" ist als die Überladung mit dem objectParameter ... weil die Konvertierung von nullnach JObject"besser" ist als die Konvertierung von nullnach object.

JObjectist spezifischer als object, weil es eine implizite Konvertierung von JObjectnach gibt object, aber nicht umgekehrt.

Wenn der letzte Parameter für die erste Methode stringstattdessen wäre (zum Beispiel), wäre keine Überladung besser als die andere, und der Aufruf wäre ohne die Umwandlung mehrdeutig.

In Abschnitt 7.5.3 der C # 5-Spezifikation finden Sie alle Einzelheiten. Insbesondere ist hier Abschnitt 7.5.3.5 ("besseres Conversion-Ziel") relevant.

Jon Skeet
quelle
8
Selbst wenn eine Umwandlung mit der Klasse, wie sie heute existiert, nicht erforderlich ist, nullwird der aufrufende Code durch das Nicht- Umwandeln der aufrufenden Code sehr spröde, da das Hinzufügen fast jeder zusätzlichen Überladung vom Referenztyp den aufrufenden Code, der nicht umwandelt, beschädigen würde. Ich würde keine Besetzung einer Nullreferenz als "redundant" betrachten, wenn es eine realistische Möglichkeit für zusätzliche Überladungen vom Referenztyp gibt, die mehrdeutig werden könnten, oder sogar in Fällen, in denen eine bestimmte Überladung von als "besser" eingestuft wird die Regeln, aber es ist alles andere als offensichtlich, dass es in jedem praktischen Sinne besser ist.
Supercat
1
Übrigens habe ich lange gedacht, dass Sprachen mit Überladung stark von der Verwendung von Attributen oder anderen Mitteln zur Angabe bestimmter Überladungen profitieren würden, wenn sie verwendbar sind, als "bevorzugt", während andere nur als "Fallbacks" betrachtet werden sollten. ;; Ich dachte auch, es wäre hilfreich, wenn eine Überladung einen Parametertyp von angeben könnte null. Kennen Sie Sprachen, die solche Dinge tun?
Supercat
@ Supercat: Nein, ich fürchte nicht.
Jon Skeet
2
@supercat: C ++ 11 und höher einführen nullptr_t, die als Parametertyp verwendet werden können. Nullzeigerliterale können jedoch immer noch implizit in Zeigertypen intund Objektzeigertypen konvertiert werden, sodass die Überlastungsauflösung nicht viel hilft. Eine nachfolgende Liste variabler Parameter ( ...) in C ++ (alle Versionen) ist ziemlich gut darin, eine bestimmte Überladung weniger bevorzugt zu machen.
Ben Voigt
8
@supercat Wenn Sie die Überladung wirklich manuell angeben möchten, warum nicht einfach eine neue Funktion mit eindeutigem Namen?
Superbest