5

(Der "benutzerdefinierte" im Titel bezieht sich auf die Tatsache, dass Addition und Subtraktion von TimeSpan und DateTime nicht Teil des C# -Standards sind definiert in der BCL.)Kuriose Überladungsauflösung bei Verwendung eines nackten Null-Literals mit benutzerdefinierten Operatoren

Herumspielen mit erhöhten Operatoren auf Nullable TimeSpan und DateTime Werte, schrieb ich den folgenden Code. Beachten Sie, dass das Framework verschiedene Operationen für TimeSpan und DateTime bietet.

Es gibt einen symmetrischen (und kommutativen) Zusatz, bei dem Sie zwei TimeSpan aufnehmen und die Summe TimeSpan zurückgeben. Die "Umkehrung" dieser Addition ist die Subtraktion von zwei TimeSpan, was zu einer TimeSpan führt.

Dann gibt es noch eine andere Art von Zusatz, asymmetrisch, wo Sie nehmen einen DateTime (linker Operand) und einen TimeSpan (rechten Operanden) ein DateTime zu erzeugen. Wegen der Asymmetrie dieser Operation hat es zwei "Arten" von Umkehrungen: Eine, wo Sie zwei DateTime voneinander subtrahieren, um die TimeSpan Differenz zu erhalten, und eine, wo Sie eine DateTime haben und davon subtrahieren TimeSpan, um ein Ergebnis DateTime zu produzieren .

static void Main() 
{ 
    DateTime? n_dt = new DateTime(2012, 12, 25); 
    TimeSpan? n_ts = TimeSpan.FromDays(62.0); 

    var a = n_dt + n_ts; // OK 
    var b = n_ts + n_ts; // OK 

    var c = null + n_dt; // OK, string concatenation! Type of expression is String 
    var d = null + n_ts; // OK, compiler prefers TS+TS, not DT+TS 
    var e = n_dt + null; // OK, DT+TS 
    var f = n_ts + null; // OK, TS+TS 
    var g = null + null; // error, type of expression is undetermined 

    var h = n_dt - n_dt; // OK 
    var i = n_dt - n_ts; // OK 
    var j = n_ts - n_ts; // OK 

    var k = null - n_dt; // OK, DT-DT 
    var l = null - n_ts; // compiler prefers TS-TS, not DT-TS 
    var m = n_dt - null; // error, compiler won't choose between DT-DT amd DT-TS, type of expression is undetermined 
    var n = n_ts - null; // OK, TS-TS 
    var o = null - null; // OK, integer subtraction! Type of expression is Nullable<Int32> 

    // illegal: 
//var p = n_dt + n_dt; 
//var q = n_ts + n_dt; 
//var r = n_ts - n_dt; 
} 

Einige Fragen entstehen natürlich.

Es ist ein bisschen seltsam, dass o erlaubt ist und gibt ein int? (warum kein long? überhaupt?), Während g nicht zulässig ist. Ist das in der Spezifikation? Außerdem ist es ein wenig seltsam, dass das "Unmögliche" c durch Zeichenkettenverkettung aufgelöst wird. Anscheinend entscheidet der Compiler, dass die null in c eine (string)null ist. Das Hinzufügen eines Ausdrucks des expliziten Typs object zu einem DateTime wird dagegen nicht kompiliert.

Aber meine Hauptfrage ist: Warum kann der Compiler eine Überlastung für d und l wählen, aber mit m klagt es über Zweideutigkeit?

+3

Bei weitem das seltsamste Ding hier ist var o = null - null; –

+0

'c' verwendet String-Verkettung, da Sprachoperatoren den benutzerdefinierten Operatoren vorgezogen werden und dieser Ausdruck dem String-Verkettungsoperator von' operator + (string, object) 'entspricht. Das wirft natürlich die Frage nach "d" auf, da durch diese Logik auch die String-Verkettung aufgelöst werden sollte. – Servy

+0

@DaveBish Einverstanden. Ich würde annehmen, dass es zwischen int/lang ambig wäre – Servy

Antwort

0

Der Grund scheint mit m, die beiden möglichen Operationen sind definiert innerhalb des gleichen Typs, nämlich System.DateTime zu sein, dass. Es gibt keine Möglichkeit, zwischen ihnen zu wählen.

Auf der anderen Seite, mit d und l wird in System.TimeSpan, und das andere ist in System.DateTime definiert eine Operation definiert. Aber in den Zeilen d und l, sehen wir TimeSpan, aber es gibt keine Erwähnung von DateTime Typ was auch immer in den Zuordnungen d und l. Es sieht so aus, als ob der Compiler nur die im Typ System.TimeSpan definierten Operatoren durchsucht und vergisst, benutzerdefinierte Operatoren zu durchsuchen, die in allen anderen Typen definiert sind (was übrigens sehr viele zu durchsuchende Typen sein würde). Auf diese Weise entdeckt der Compiler während der Auflösung von d und l niemals die Operatoren, die innerhalb des Typs DateTime definiert sind.

+1

Siehe Abschnitt 7.3.4 der C# -Spezifikation, da dies relevant erscheint und diese Antwort bestätigt wird. – Servy

+0

"Übrigens" in der Tat. – phoog