ここには 2 つの問題があります。1) Type が null 可能かどうかを確認するためのテスト。2) オブジェクトが null 許容型を表しているかどうかを確認するためのテスト。
問題 1 (タイプのテスト) については、私が自分のシステムで使用したソリューションを次に示します: TypeIsNullable-check ソリューション
問題 2 (オブジェクトのテスト) については、上記の Dean Chalk のソリューションは値型に対しては機能しますが、<T> オーバーロードを使用すると常に false が返されるため、参照型に対しては機能しません。参照型は本質的に null 許容であるため、参照型をテストすると常に true が返されます。これらのセマンティクスの説明については、以下の ["nullability" について] の注を参照してください。したがって、ディーンのアプローチに対する私の修正は次のとおりです。
public static bool IsObjectNullable<T>(T obj)
{
// If the parameter-Type is a reference type, or if the parameter is null, then the object is always nullable
if (!typeof(T).IsValueType || obj == null)
return true;
// Since the object passed is a ValueType, and it is not null, it cannot be a nullable object
return false;
}
public static bool IsObjectNullable<T>(T? obj) where T : struct
{
// Always return true, since the object-type passed is guaranteed by the compiler to always be nullable
return true;
}
上記のソリューションの client-test コードに対する私の変更は次のとおりです。
int a = 123;
int? b = null;
object c = new object();
object d = null;
int? e = 456;
var f = (int?)789;
string g = "something";
bool isnullable = IsObjectNullable(a); // false
isnullable = IsObjectNullable(b); // true
isnullable = IsObjectNullable(c); // true
isnullable = IsObjectNullable(d); // true
isnullable = IsObjectNullable(e); // true
isnullable = IsObjectNullable(f); // true
isnullable = IsObjectNullable(g); // true
IsObjectNullable<T>(T t) で Dean のアプローチを変更した理由は、彼の元のアプローチでは参照型に対して常に false が返されたためです。IsObjectNullable のようなメソッドは参照型の値を処理できる必要があり、すべての参照型は本質的に null 許容であるため、参照型または null が渡された場合、メソッドは常に true を返す必要があります。
上記の 2 つのメソッドは、次の単一のメソッドに置き換えて、同じ出力を得ることができます。
public static bool IsObjectNullable<T>(T obj)
{
Type argType = typeof(T);
if (!argType.IsValueType || obj == null)
return true;
return argType.IsGenericType && argType.GetGenericTypeDefinition() == typeof(Nullable<>);
}
ただし、この最後の単一メソッドのアプローチの問題は、Nullable<T> パラメーターを使用するとパフォーマンスが低下することです。IsObjectNullable 呼び出しで Nullable<T> 型のパラメーターが使用されている場合に、コンパイラが前に示した 2 番目のメソッド オーバーロードを選択できるようにするよりも、この 1 つのメソッドの最後の行を実行するのにはるかに多くのプロセッサ時間がかかります。したがって、最適な解決策は、ここで説明する 2 つの方法のアプローチを使用することです。
注意: このメソッドは、例に示すように、元のオブジェクト参照または正確なコピーを使用して呼び出された場合にのみ確実に機能します。ただし、nullable オブジェクトが元の Nullable<> フォームのままではなく、別のタイプ (オブジェクトなど) にボックス化されている場合、このメソッドは確実に機能しません。このメソッドを呼び出すコードが元のボックス化されていないオブジェクト参照または正確なコピーを使用していない場合、このメソッドを使用してオブジェクトの null 可能性を確実に判断することはできません。
ほとんどのコーディング シナリオでは、null 可能性を判断するために、参照ではなく、元のオブジェクトの Type をテストする必要があります (たとえば、null 可能性を判断するには、コードがオブジェクトの元の Type にアクセスできる必要があります)。これらのより一般的なケースでは、IsTypeNullable (リンクを参照) が null 可能性を判断する信頼できる方法です。
PS - 「nullability」について
別の投稿で行った nullability についての声明を繰り返す必要があります。これは、このトピックに適切に対処することに直接適用されます。つまり、ここでの議論の焦点は、オブジェクトが一般的な Nullable 型であるかどうかを確認する方法ではなく、その型のオブジェクトに null の値を割り当てることができるかどうかにあると思います。つまり、オブジェクト型が Nullable かどうかではなく、nullable かどうかを判断する必要があると思います。違いはセマンティクスにあります。つまり、null 可能性を判断するための実際的な理由であり、通常はそれだけが重要です。
実行時まで不明なタイプのオブジェクト (Web サービス、リモート呼び出し、データベース、フィードなど) を使用するシステムでは、一般的な要件は、オブジェクトに null を割り当てることができるかどうか、またはオブジェクトに含まれている可能性があるかどうかを判断することです。ヌル。null 非許容型に対してこのような操作を実行すると、エラー (通常は例外) が発生する可能性が高く、パフォーマンスとコーディング要件の両方の点で非常にコストがかかります。このような問題を事前に回避するという非常に好ましいアプローチを取るには、任意の Type のオブジェクトが null を含むことができるかどうかを判断する必要があります。つまり、一般的に「nullable」かどうか。
非常に実用的で典型的な意味で、.NET 用語での null 可能性は、必ずしもオブジェクトの Type が Nullable の形式であることを意味するわけではありません。実際、多くの場合、オブジェクトには参照型があり、null 値を含むことができるため、すべて null 許容です。これらのどれも Nullable 型を持っていません。したがって、ほとんどのシナリオで実用的な目的のために、nullable の一般的な概念と、実装に依存する Nullable の概念についてテストを行う必要があります。そのため、.NET の Nullable 型だけに注目することにこだわるのではなく、その要件と動作に関する理解を取り入れて、null 可能性の一般的で実用的な概念に注目する必要があります。