この問題について詳しく説明しているMicrosoft Connect の記事を見つけることができました。
残念ながら、この動作は仕様によるものであり、値の型を含む可能性のある型パラメーターを使用できるようにする簡単な解決策はありません。
型が参照型であることがわかっている場合、型が独自のカスタム オーバーロードを指定することはできますが、define on object の既定のオーバーロードは参照の等価性について変数をテストします。コンパイラは、変数の静的な型に基づいて、使用するオーバーロードを決定します (決定はポリモーフィックではありません)。したがって、ジェネリック型パラメーター T を封印されていない参照型 (Exception など) に制約するように例を変更すると、コンパイラは使用する特定のオーバーロードを決定でき、次のコードがコンパイルされます。
public class Test<T> where T : Exception
型が値型であることがわかっている場合は、使用されている正確な型に基づいて特定の値の等価性テストを実行します。参照の比較は値の型では意味がなく、コンパイラはどの特定の値の比較を発行するかを知ることができないため、ここでは適切な「デフォルト」の比較はありません。コンパイラは ValueType.Equals(Object) への呼び出しを発行できますが、このメソッドはリフレクションを使用しており、特定の値の比較に比べて非常に非効率的です。したがって、T に値の型の制約を指定したとしても、コンパイラがここで生成することは合理的ではありません。
public class Test<T> where T : struct
あなたが提示した場合、コンパイラは T が値型なのか参照型なのかさえわからない場合、同様に、可能なすべての型に対して有効な生成物は何もありません。参照比較は値型に対して有効ではなく、オーバーロードされていない参照型に対しては、ある種の値比較は予期されません。
これがあなたができることです...
これらのメソッドの両方が、参照型と値型の一般的な比較に機能することを確認しました。
object.Equals(param, default(T))
また
EqualityComparer<T>.Default.Equals(param, default(T))
「==」演算子で比較するには、次のいずれかの方法を使用する必要があります。
T のすべてのケースが既知の基本クラスから派生している場合、ジェネリック型の制限を使用してコンパイラに知らせることができます。
public void MyMethod<T>(T myArgument) where T : MyBase
次に、コンパイラは操作を実行する方法を認識し、現在表示されMyBase
ている「演算子 '==' はタイプ 'T' および 'T' のオペランドに適用できません」というエラーをスローしません。
別のオプションは、 T を実装する任意の型に制限することIComparable
です。
public void MyMethod<T>(T myArgument) where T : IComparable
そして、 IComparable インターフェイスCompareTo
で定義されたメソッドを使用します。