Ich konnte einen Microsoft Connect-Artikel finden , in dem dieses Problem ausführlich behandelt wird:
Leider ist dieses Verhalten beabsichtigt und es gibt keine einfache Lösung, um die Verwendung von Typparametern zu ermöglichen, die Werttypen enthalten können.
Wenn bekannt ist, dass es sich bei den Typen um Referenztypen handelt, testet die Standardüberladung der auf Objekt definierten Variablen die Referenzgleichheit, obwohl ein Typ möglicherweise eine eigene benutzerdefinierte Überladung angibt. Der Compiler bestimmt anhand des statischen Typs der Variablen, welche Überladung verwendet werden soll (die Bestimmung ist nicht polymorph). Wenn Sie Ihr Beispiel ändern, um den generischen Typparameter T auf einen nicht versiegelten Referenztyp (z. B. Ausnahme) zu beschränken, kann der Compiler daher die zu verwendende spezifische Überladung ermitteln und den folgenden Code kompilieren:
public class Test<T> where T : Exception
Wenn bekannt ist, dass es sich bei den Typen um Werttypen handelt, werden basierend auf den genauen verwendeten Typen spezifische Wertgleichheitstests durchgeführt. Hier gibt es keinen guten "Standard" -Vergleich, da Referenzvergleiche für Werttypen nicht aussagekräftig sind und der Compiler nicht wissen kann, welcher spezifische Wertvergleich ausgegeben werden soll. Der Compiler könnte einen Aufruf von ValueType.Equals (Object) ausgeben, aber diese Methode verwendet Reflektion und ist im Vergleich zu den spezifischen Wertvergleichen ziemlich ineffizient. Selbst wenn Sie eine Werttypbeschränkung für T angeben, kann der Compiler hier daher nichts generieren:
public class Test<T> where T : struct
In dem von Ihnen vorgestellten Fall, in dem der Compiler nicht einmal weiß, ob T ein Wert oder ein Referenztyp ist, muss ebenfalls nichts generiert werden, was für alle möglichen Typen gültig wäre. Ein Referenzvergleich wäre für Werttypen nicht gültig, und ein Wertvergleich wäre für Referenztypen, die nicht überladen sind, unerwartet.
Folgendes können Sie tun ...
Ich habe bestätigt, dass beide Methoden für einen generischen Vergleich von Referenz- und Werttypen funktionieren:
object.Equals(param, default(T))
oder
EqualityComparer<T>.Default.Equals(param, default(T))
Um Vergleiche mit dem Operator "==" durchzuführen, müssen Sie eine der folgenden Methoden verwenden:
Wenn alle Fälle von T von einer bekannten Basisklasse stammen, können Sie den Compiler mithilfe generischer Typbeschränkungen informieren.
public void MyMethod<T>(T myArgument) where T : MyBase
Der Compiler erkennt dann, wie Operationen ausgeführt werden MyBase
und gibt nicht aus, dass der Operator "==" nicht auf Operanden vom Typ "T" und "T" angewendet werden kann, die jetzt angezeigt werden.
Eine andere Möglichkeit wäre, T auf jeden Typ zu beschränken, der implementiert IComparable
.
public void MyMethod<T>(T myArgument) where T : IComparable
Verwenden Sie dann die CompareTo
von der IComparable-Schnittstelle definierte Methode .
if (myArgument?.Equals( default(T) ) != null )
.