Beginnen wir mit einem sehr einfachen Code:
%Vor%Das Ergebnis ist 4xtrue. Ändern wir nun den Typ einer Variablen d in dezimal? :
%Vor%Diesmal wird das Ergebnis Wahr, Wahr, Falsch, Wahr sein. Die Erklärung dieser Situation ist ziemlich einfach. Die Equals -Methode wird wie folgt für Nullable & lt; T & gt; -Typ implementiert:
%Vor%Wenn this einen Wert hat und anderer -Parameter nicht null ist, wird Decimal.Equals (Objektwert) aufgerufen. Decimal.Equals (Objektwert) -Methode funktioniert auf diese Weise, wenn der Wert -Parameter nicht dezimal ist, dann wird das Ergebnis immer sein falsch .
Mir scheint, dass die aktuelle Implementierung nicht intuitiv ist und ich frage mich, warum Nullable
War es absichtlich oder ist es eine Unterlassung?
Kommentar 1:
Ein kurzer Kommentar um klar zu sein. Ich schlug vor, dass Nullable & lt; T & gt; zwei Equals -Methoden haben sollte, dh: public override bool Equals (anderes Objekt) und public bool Equals (T andere)
Anstatt (decimal)2
zu schreiben, kannst du 2m
schreiben (wird das im folgenden verwenden).
Wenn Sie den Operator ==
verwenden, tritt kein Boxing auf. Der C # -Compiler wählt die vordefinierte Überladung (d. H. Die in der C # -Sprachspezifikation definierte Überladung; dies ist nicht notwendigerweise eine echte .NET-Methode) von operator ==
, die am besten übereinstimmt.
Es gibt Überladungen:
%Vor% Es gibt keine "gemischten" Überladungen wie operator ==(decimal x, int y);
. Da eine implizite Konvertierung von int
nach decimal
existiert, wird Ihr Literal 2
implizit in 2m
konvertiert, wenn Sie ==
verwenden.
Mit Equals
tritt in manchen Situationen boxen auf. Dafür brauchst du keine Nullables. Um all diese Aufrufe zu nennen:
gib false
zurück! "Zwei" vom Typ Int32
ist nicht gleich "zwei" vom Typ Decimal
.
Nur wenn das Überladen der Methode zu einer Konvertierung zwischen int
und decimal
führt, ist das Ergebnis true
. Zum Beispiel:
Obwohl eine zusätzliche Überladung von Equals
zu Nullable<>
hinzugefügt werden konnte, ist das von Ihnen beschriebene Verhalten nicht wirklich auf Nullable<>
bezogen.
Obwohl mir diese Fragen gefallen, können sie nur von denen des verantwortlichen Designteams beantwortet werden. Eine offensichtliche Problemumgehung besteht darin, auf das Value
zuzugreifen, das T
ist, und das Equals
davon zu verwenden.
Meine beste Schätzung ist, dass es wahrscheinlich alle T
zu IEquatable<T>
zwingen würde, um generisch auf Equals<T>
auf einen bestimmten Typ zuzugreifen. Dies würde für die Kernwerktypen funktionieren, aber andere .NET-Strukturen würden diese Schnittstelle nicht unbedingt implementieren und enum
-Typen nicht.
Ich nehme an, es könnte mit type checking / casting gemacht werden, aber das kostet dann viel Arbeit im Vergleich zum Aufrufer einfach: myNullable.GetValueOrDefault().Equals()
.
Sie können eine Erweiterungsmethode für diese Aufgabe erstellen, damit sie die Methode aufruft, die Sie benötigen, um das generische Argument explizit anzugeben (andernfalls ruft der Compiler Equals(object)
:
Ich habe eine Frage gestellt, warum dieser Anruf wird benötigt.
Der Grund, warum es in die Erweiterungsmethode gezwungen werden muss, liegt an der Compilerimplementierung, die nur Erweiterungsmethoden verwendet, wenn keine geeignete Methode existiert. In diesem Fall wird Equals(object)
als geeigneter als Equals<T>(T)
als letzter angesehen ist eine Erweiterungsmethode. Es ist in der Spezifikation.