この問題について詳しく説明しているMicrosoft Connectの記事を見つけることができました。
残念ながら、この動作は仕様によるものであり、値型を含む可能性のある型パラメーターでの使用を可能にする簡単な解決策はありません。
型が参照型であることがわかっている場合、define onオブジェクトのデフォルトのオーバーロードは、参照の等価性について変数をテストしますが、型は独自のカスタムオーバーロードを指定する場合があります。コンパイラーは、変数の静的タイプに基づいて、使用するオーバーロードを決定します(決定はポリモーフィックではありません)。したがって、例を変更してジェネリック型パラメーターTを封印されていない参照型(例外など)に制約すると、コンパイラーは使用する特定のオーバーロードを判別でき、次のコードがコンパイルされます。
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
次にCompareTo
、IComparableインターフェイスで定義されたメソッドを使用します。
if (myArgument?.Equals( default(T) ) != null )
ます。