ここには2つの問題があります。1)Typeがnull可能かどうかを確認するテスト。2)オブジェクトがnull許容型を表すかどうかを確認するためのテスト。
問題1(タイプのテスト)について、私が自分のシステムで使用したソリューションは次のとおりです:TypeIsNullable-checkソリューション
問題2(オブジェクトのテスト)の場合、上記のDean Chalkのソリューションは値型に対しては機能しますが、<T>オーバーロードを使用すると常にfalseが返されるため、参照型に対しては機能しません。参照型は本質的にnull可能であるため、参照型をテストすると常にtrueが返されます。これらのセマンティクスの説明については、下記の「null可能性について」の注記を参照してください。したがって、ここにディーンのアプローチへの私の変更があります:
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;
}
上記のソリューションのクライアントテストコードに対する私の変更は次のとおりです。
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番目のメソッドオーバーロードを選択できるようにするよりも、この単一メソッドの最後の行を実行するのにはるかに多くのプロセッサ時間がかかります。したがって、最適なソリューションは、ここに示す2つの方法のアプローチを使用することです。
警告:このメソッドは、例に示すように、元のオブジェクト参照または正確なコピーを使用して呼び出された場合にのみ確実に機能します。ただし、null許容オブジェクトが元のNullable <>フォームのままではなく、別のType(オブジェクトなど)にボックス化されている場合、このメソッドは確実に機能しません。このメソッドを呼び出すコードが元のボックス化されていないオブジェクト参照または正確なコピーを使用していない場合、このメソッドを使用してオブジェクトのnull可能性を確実に判断することはできません。
ほとんどのコーディングシナリオでは、null可能かどうかを判断するには、参照ではなく元のオブジェクトのタイプのテストに依存する必要があります(たとえば、null可能かどうかを判断するには、コードがオブジェクトの元のタイプにアクセスできる必要があります)。これらのより一般的なケースでは、IsTypeNullable(リンクを参照)は、ヌル可能性を判断する信頼できる方法です。
PS-「nullability」について
私は別の投稿で私が作ったヌル可能性についての声明を繰り返す必要があります。これは、このトピックに適切に対処するために直接適用されます。つまり、ここでの議論の焦点は、オブジェクトが汎用のNullable型であるかどうかを確認する方法ではなく、その型のオブジェクトにnullの値を割り当てることができるかどうかにあると考えています。つまり、オブジェクト型がnull可能かどうかではなく、null可能かどうかを判断する必要があると思います。違いはセマンティクス、つまりnull可能かどうかを決定する実際的な理由にあります。これは通常重要なことです。
実行時まで不明である可能性のあるタイプのオブジェクト(Webサービス、リモート呼び出し、データベース、フィードなど)を使用するシステムでは、一般的な要件は、オブジェクトにnullを割り当てることができるかどうか、またはオブジェクトにnull。nullを許容しない型でこのような操作を実行すると、エラー(通常は例外)が発生する可能性が高く、パフォーマンスとコーディング要件の両方の面で非常にコストがかかります。このような問題を積極的に回避するという非常に好ましいアプローチをとるには、任意のTypeのオブジェクトがnullを含むことができるかどうかを判断する必要があります。つまり、一般に「null可能」かどうか。
非常に実用的で一般的な意味で、.NET用語のnull可能性は、オブジェクトのTypeがNullableの形式であることを必ずしも意味しません。実際、多くの場合、オブジェクトには参照型があり、null値を含めることができるため、すべてnull可能です。これらのどれもNullableタイプを持ちません。したがって、ほとんどのシナリオでの実用的な目的のために、実装に依存するNullableの概念ではなく、Null可能性の一般的な概念に対してテストを行う必要があります。したがって、.NET Nullable型のみに焦点を当てることでハングアップするのではなく、NULL可能性の一般的で実用的な概念に焦点を合わせるプロセスに、その要件と動作の理解を組み込む必要があります。