オブジェクトがnull可能かどうかを確認する方法は?


202

特定のオブジェクトがnull可能かどうかを確認する方法、つまり次のメソッドを実装する方法...

bool IsNullableValueType(object o)
{
    ...
}

編集:私はnullable値タイプを探しています。ref型は考えていませんでした。

//Note: This is just a sample. The code has been simplified 
//to fit in a post.

public class BoolContainer
{
    bool? myBool = true;
}

var bc = new BoolContainer();

const BindingFlags bindingFlags = BindingFlags.Public
                        | BindingFlags.NonPublic
                        | BindingFlags.Instance
                        ;


object obj;
object o = (object)bc;

foreach (var fieldInfo in o.GetType().GetFields(bindingFlags))
{
    obj = (object)fieldInfo.GetValue(o);
}

objは、値がに等しいタイプboolSystem.Boolean)のオブジェクトを参照するようになりましたtrue。私が本当に欲しかったのはタイプのオブジェクトでしたNullable<bool>

そこで、回避策として、私はoがnull可能かどうかを確認し、objの周りにnull可能ラッパーを作成することにしました。


コードにはnull可能として文字列を含める必要がありますか?これらはnull可能と思われる非ジェネリックのValueTypeです。または、それらはValueTypeではありませんか?
TamusJRoyce

文字列はValueTypeではありません。参照型です。
Suncat2000 2013年

これは本当に良い質問です!'Type.IsNullableType()'は、実際には 'Nullable <T>'であるタイプのみをチェックするため、一種の欺瞞です。nullを受け入れることができるタイプを実際にチェックしたい場合、期待される結果を返しませんでした。値(たとえば、a.IsNullableType()で使用しようとしました。ここで、「a」は実行時に決定される「typeof(string)」
でした

回答はfieldInfo.FieldTypeにあります。FieldTypeがジェネリックで、ジェネリックタイプがNullable <>タイプかどうかを確認してください。(例:if(FieldType.IsGenericType && FieldType.GetGenericTypeDefinition()== typeof(Nullable <>))))。obj.GetType()を取得しようとしないでください。UndelyingSystemTypeにNullable <T>変数T(ブール型の場合はNullable <Boolean>ではなく)が含まれます。これはボクシングの問題です。
SoLaR

回答:


271

nullableには2つのタイプがあります- Nullable<T>とreference-typeです。

ジョンは、ボックス化されているとタイプを取得するのが難しいことを修正しましたが、ジェネリックスを使用してこれを行うことができます。これは実際にはtypeをテストTしていobjますが、純粋にジェネリック型の推論のためにパラメーターを使用しています(呼び出しを簡単にするため)obj。ただし、パラメーターがなくてもほとんど同じように機能します。

static bool IsNullable<T>(T obj)
{
    if (obj == null) return true; // obvious
    Type type = typeof(T);
    if (!type.IsValueType) return true; // ref-type
    if (Nullable.GetUnderlyingType(type) != null) return true; // Nullable<T>
    return false; // value-type
}

しかし、値をオブジェクト変数に既にボックス化している場合、これはあまりうまく機能しません。

Microsoftのドキュメント:https : //docs.microsoft.com/en-us/dotnet/csharp/programming-guide/nullable-types/how-to-identify-a-nullable-type


7
最後の行は、Tに直接ボックス化するのではなく、なんとかボックス化されたNullable <T>をなんとかして取得した場合にのみ有効です。可能ですが、覚えていることから達成するのは難しいです。
Jon Skeet

このコードは私にとって役に立ちました。ボックス化されたNullable <T>を取得したからではなく、汎用のWPFコンバーターの基本クラスを記述していて、一部のプロパティがnull値であるため、Nullable.GetUnderlyingTypeを使用してそのケースを検出し、Activator.CreateInstanceを作成しました。ボックス化されたnull可能(Convert.ChangeTypeはnull可能を処理しません)
Qwertie

1
@アベルは、彼が参照型を考慮していないことを明確にするために彼の編集を意味している場合、私の回答はその編集よりも先だったと思います。読者は、自分のニーズに基づいて、自分の決定をそこで行うことができると私は思います(確認:14:42に追加されたref-typesに関するコメント;私の答えはすべて<= 14:34)
Marc Gravell

1
(obj == null)は、obj = 1のときに例外をスローしますか?
Qi Fan

3
@JustinMorgan Tがによって制約されているジェネリックパラメータの場合T : structTは許可されないNullable<>ため、その場合はチェックする必要はありません。型Nullable<>が構造体であることはわかっていますが、C#では、制約によりwhere T : structnull許容値型が明確に除外されます。仕様では、「値型として分類されていますが、null許容型(4.1.10)は値型の制約を満たしていません。」
Jeppe Stig Nielsen

46

メソッドのオーバーロードを使用する非常に簡単な解決策があります

http://deanchalk.com/is-it-nullable/

抜粋:

public static class ValueTypeHelper
{
    public static bool IsNullable<T>(T t) { return false; }
    public static bool IsNullable<T>(T? t) where T : struct { return true; }
}

その後

static void Main(string[] args)
{
    int a = 123;
    int? b = null;
    object c = new object();
    object d = null;
    int? e = 456;
    var f = (int?)789;
    bool result1 = ValueTypeHelper.IsNullable(a); // false
    bool result2 = ValueTypeHelper.IsNullable(b); // true
    bool result3 = ValueTypeHelper.IsNullable(c); // false
    bool result4 = ValueTypeHelper.IsNullable(d); // false
    bool result5 = ValueTypeHelper.IsNullable(e); // true
    bool result6 = ValueTypeHelper.IsNullable(f); // true

7
さらに、テストケースを追加するための1つ。これらのテストケースを使用して、他のすべての回答を確認しました。より多くの人がこの余分なビットを移動する必要があります。
Marty Neal

4
価値があるので、これはVB.NETでは機能しません。返されるすべての状況で、「これらの引数に最も具体的なアクセス可能な 'IsNullable'がないため、オーバーロードの解決に失敗しました」というコンパイラエラーが発生しますTrue
ckittel

1
私はこのソリューションが本当に好きです-そしてVBがそれを処理できないのは残念です。私はValueTypeにして周りの作業が、VBコンパイラは、それが共有方法や拡張機能として呼ばれたかどうかに基づいて使用するオーバーロードどの矛盾しているとのトラブルに遭遇してみました、それは奇妙なようだと、私もこのことについて疑問を提起した:stackoverflow.com/質問/ 12319591 /…
James Close

22
コンパイル時の型をチェックしていますが、コンパイル時の型がnull許容(System.Nullable<>)かどうかは(インテリセンスから)すでに明らかです。あなたが言う場合はobject g = e;、その後ValueTypeHelper.IsNullable(g)、何を得るために期待していますか?
Jeppe Stig Nielsen

18
確認しました。Jeppeが言ったように、これは機能しません。変数がオブジェクトにキャストされた場合、常にfalseが返されます。したがって、この方法では、実行時に不明なオブジェクトのタイプを判別できません。これが機能するのは、型がコンパイル時に固定されている場合のみで、その場合はランタイムチェックはまったく必要ありません。
HugoRune 2013

30

「型がnull可能かどうかを確認する方法」の質問 これは実際には「型がNullable<>?かどうかを確認する方法」であり、これは「型が何らかのジェネリック型の構築型かどうかを確認する方法?」に一般化できるため、「Is Nullable<int>a Nullable<>?」という質問に答えるだけではありません。だけでなく、「です?」。List<int>List<>

提供されているソリューションのほとんどはこのNullable.GetUnderlyingType()メソッドを使用しています。これは明らかにの場合にのみ機能しNullable<>ます。ジェネリック型で機能する一般的なリフレクションソリューションは見当たらないので、この質問はすでにかなり前に回答されていますが、後世のためにここに追加することにしました。

型がNullable<>リフレクションを使用する何らかの形であるかどうかを確認するには、まず、作成したジェネリック型を、たとえばNullable<int>、ジェネリック型定義に変換する必要がありますNullable<>。クラスのGetGenericTypeDefinition()メソッドを使用してそれを行うことができますType。次に、結果の型を次と比較できますNullable<>

Type typeToTest = typeof(Nullable<int>);
bool isNullable = typeToTest.GetGenericTypeDefinition() == typeof(Nullable<>);
// isNullable == true

同じことがすべてのジェネリック型に適用できます。

Type typeToTest = typeof(List<int>);
bool isList = typeToTest.GetGenericTypeDefinition() == typeof(List<>);
// isList == true

いくつかの型は同じように見えるかもしれませんが、型引数の数が異なるということは、完全に異なる型であることを意味します。

Type typeToTest = typeof(Action<DateTime, float>);
bool isAction1 = typeToTest.GetGenericTypeDefinition() == typeof(Action<>);
bool isAction2 = typeToTest.GetGenericTypeDefinition() == typeof(Action<,>);
bool isAction3 = typeToTest.GetGenericTypeDefinition() == typeof(Action<,,>);
// isAction1 == false
// isAction2 == true
// isAction3 == false

以来Type、オブジェクトがタイプごとに一度インスタンス化されている、あなたはそれらの間の基準の等価性をチェックすることができます。したがって、2つのオブジェクトが同じジェネリック型定義であるかどうかを確認する場合は、次のように記述できます。

var listOfInts = new List<int>();
var listOfStrings = new List<string>();

bool areSameGenericType =
    listOfInts.GetType().GetGenericTypeDefinition() ==
    listOfStrings.GetType().GetGenericTypeDefinition();
// areSameGenericType == true

オブジェクトがnullではなく、null可能かどうかを確認する場合はType、上記の手法をMarc Gravellのソリューションと組み合わせて、かなり単純なメソッドを作成できます。

static bool IsNullable<T>(T obj)
{
    if (!typeof(T).IsGenericType)
        return false;

    return typeof(T).GetGenericTypeDefinition() == typeof(Nullable<>);
}

@ AllonGuralnek私の答えの下に簡略化されたバージョンがあります。私はそれを編集として作りたかったし、私の評判はあなたのレベルではないので、あなたの答えに私の名前がなければ編集されるだろう、それでも、レビューは常に私の脚に飛び込んでいるようだない。奇妙な世界、一部の人々は定義を得ません:)。
ipavlu 2015年

@ipavlu:あなたのバージョンは単純化されておらず、実際にはもっと複雑です。結果をキャッシュするので、最適化されていると思います。そのため、理解が難しくなります。
Allon Guralnek 2015年

@ AllonGuralnek静的ジェネリッククラスと静的な一度初期化されたフィールド、それは複雑ですか?親愛なる神様、私は恐ろしい犯罪をしました:)。
ipavlu 2015

@ipavku:はい、「オブジェクトがnull可能かどうかを確認する方法」という質問とは関係がないためです。私はそれをシンプルかつ要点を保つようにし、不要で無関係な概念を導入することは避けます。
Allon Guralnek、2015

1
@nawfal:私があなたを正しく理解していればNullable.GetUnderlyingType()、フレームワークによってすでに提供されているものの存在に直面して私の実装を探求している。フレームワークでメソッドを使用しないのはなぜですか?そうですね。それはより明確で、より簡潔で、よりよくテストされています。しかし、私の記事では、リフレクションを使用して必要な情報を取得する方法を教えて、誰かが任意のタイプに適用できるようにしています(typeof(Nullable<>)他のタイプに置き換えることで)。GetUnderlyingType()(元のまたは逆コンパイルされた)のソースを見ると、それが私のコードに非常に似ていることがわかります。
Allon Guralnek 16

30

これは私にとってはうまくいき、簡単に見えます:

static bool IsNullable<T>(T obj)
{
    return default(T) == null;
}

値タイプの場合:

static bool IsNullableValueType<T>(T obj)
{
    return default(T) == null && typeof(T).BaseType != null && "ValueType".Equals(typeof(T).BaseType.Name);
}

7
それは価値があることのために、これはマイクロソフトによって使用され
canton7

1
いいですね…これは後で来た一番の答えではありませんか?私はトップの答えがとても混乱していると思います。
ヴィンセントBuscarello

1
これが一番の答えです。さまざまな方法を何日か試した後、この解決策をランダムに考えて試してみましたが、完全に機能しているようです(最高の回答と比較して)
user3163495

2
これは、インスタンスをNULLに設定できるかどうかを調べる優れたソリューションですが、通常のオブジェクトを含め、nullに設定できるすべての場合にtrueを返します。元の質問がNullable ValueTypeを検出することを特に望んでいたことを認識することが重要です。
JamesHoux

20

まあ、あなたは使うことができます:

return !(o is ValueType);

...しかし、オブジェクト自体はnull可能ではないか、そうでなければ- はnull です。これをどのように使用する予定でしたか?


2
これは私を少し失望させました。例えばint?i = 5; typeof(i)はNullable <Int32>の代わりにSystem.Int32を返します-typeof(int?)はNullable <Int32>を返します。このトピックに関する明確な説明はどこにありますか?
岐阜県

2
typeof(i)はコンパイラエラーを発生させます。変数でtypeofを使用することはできません。実際に何をしましたか?
Jon Skeet、

15
i.GetType()は最初にオブジェクトにボックス化し、ボックス化されたnull許容型などはありません-Nullable <int>はnull参照またはボックス化intにボックス化されます。
Jon Skeet、

その方法はNullable.GetUnderlyingType(type)!= nullよりも優れています。
Kiquenet 2013年

@Kiquenet:ここにはタイプありません-値だけです。
Jon Skeet 2013年

11

私が理解できる最も簡単な方法は:

public bool IsNullable(object obj)
{
    Type t = obj.GetType();
    return t.IsGenericType 
        && t.GetGenericTypeDefinition() == typeof(Nullable<>);
}

+1。ボックス化されたnull許容型の優れたソリューション。私はまだこれを具体的にテストしていません。ですので、他の誰かが確認できれば、ありがたいです。
TamusJRoyce

私はすでにそれをテストしました。一種のNullableタイプを作成する必要がありましたが、セマンティクスが異なりました。私の状況では、私nullは有効な値としてサポートし、値はまったくサポートしない必要があります。したがって、Optional型が作成されました。null値をサポートする必要があるためNullable、実装の一部として値を処理するためのコードも実装する必要がありました。これがこのコードの由来です。
CARLOS LOTH

9
この解決策は間違っていると思います。Nullable値型を引数として、型オブジェクトのパラメーターを想定しているメソッドに渡すと、ボクシングが発生するはずです。Nullableは値型であり、ボクシング変換の結果は参照型です。ボックス化されたnullableはありません。このメソッドは常にfalseを返すと思いますか?
Mishax 2012年

1
別の答えのようなそれについてのテスト?
Kiquenet 2013年

5
ボクシング値のため、機能しません。常にFALSEを返します。
Nロッキング14

10

ここには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可能性の一般的で実用的な概念に焦点を合わせるプロセスに、その要件と動作の理解を組み込む必要があります。


8

私が思いついた最も簡単なソリューションは、Microsoftのソリューション(方法:null可能な型を特定する(C#プログラミングガイド))を拡張メソッドとして実装することです。

public static bool IsNullable(this Type type)
{
    return Nullable.GetUnderlyingType(type) != null;
}

これは次のように呼び出すことができます:

bool isNullable = typeof(int).IsNullable();

これは、クラスのIsNullable()他のすべてのIsXxxx()メソッドに適合するため、アクセスするのにも論理的な方法のようTypeです。


1
「!=」の代わりに「==」を使用しませんでしたか?
vkelman

良い点@vkelmanその変更を行う代わりに、Microsoftからの現在の提案を使用するように回答を更新しました。これは、私がこれを書いて以来変更されているためです。
sclarke81

6

null許容型(Nullable<int>またはint?など)をボックス化するときは注意してください。

int? nullValue = null;
object boxedNullValue = (object)nullValue;
Debug.Assert(boxedNullValue == null);

int? value = 10;
object boxedValue = (object)value;
Debug.Assert( boxedValue.GetType() == typeof(int))

これは真の参照型になるため、null可能であったという事実を失います。


3

トピックから少し外れたかもしれませんが、それでも興味深い情報がいくつかあります。Nullable.GetUnderlyingType() != null型がnull可能である場合、ID を使用する人がたくさんいます。これは明らかに機能しますが、Microsoftは次のようにアドバイスしていますtype.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)http://msdn.microsoft.com/en-us/library/ms366789.aspxを参照)。

これをパフォーマンスの面から見ました。以下のテスト(100万回の試行)の結論は、型がnull許容の場合、Microsoftオプションが最高のパフォーマンスを提供するということです。

Nullable.GetUnderlyingType(): 1335ms(3倍遅い)

GetGenericTypeDefinition()== typeof(Nullable <>): 500 ミリ秒

私たちは少しの時間について話していることを知っていますが、誰もがミリ秒を微調整するのが大好きです:-)!ですから、上司が数ミリ秒の短縮を望んでいるなら、これがあなたの救世主です...

/// <summary>Method for testing the performance of several options to determine if a type is     nullable</summary>
[TestMethod]
public void IdentityNullablePerformanceTest()
{
    int attempts = 1000000;

    Type nullableType = typeof(Nullable<int>);

    Stopwatch stopwatch = new Stopwatch();
    stopwatch.Start();
    for (int attemptIndex = 0; attemptIndex < attempts; attemptIndex++)
    {
        Assert.IsTrue(Nullable.GetUnderlyingType(nullableType) != null, "Expected to be a nullable"); 
    }

    Console.WriteLine("Nullable.GetUnderlyingType(): {0} ms", stopwatch.ElapsedMilliseconds);

    stopwatch.Restart();

    for (int attemptIndex = 0; attemptIndex < attempts; attemptIndex++)
   {
       Assert.IsTrue(nullableType.IsGenericType && nullableType.GetGenericTypeDefinition() == typeof(Nullable<>), "Expected to be a nullable");
   }

   Console.WriteLine("GetGenericTypeDefinition() == typeof(Nullable<>): {0} ms", stopwatch.ElapsedMilliseconds);
   stopwatch.Stop();
}

1
こんにちは、おそらく時間の測定に1つの問題があります。アサートは結果に影響を与える可能性があります。Assertなしでテストしましたか?また、Console.WriteLineはメーター領域の外側にある必要があります。パフォーマンスの問題を定量化する試みの場合は+1 :)。
ipavlu 2015

@ipavlu Console.WriteLineは確かにメーター制エリア外です;)
nawfal

Roelは、ipavluが述べたようにAssert、ループの外にいる必要があります。次に、null以外の値に対してもテストして、偽のケースをテストする必要があります。私は同様のテスト(nulableが2つ、null可能でないものが4つ)を実行しGetUnderlyingType、で〜2 秒、で〜1 秒GetGenericTypeDefinition、つまりGetGenericTypeDefinition2倍高速になりました(3倍ではありません)。
nawfal

2つのnullablesと2つのnon-nullablesで別のラウンドを行いました-今回GetUnderlyingTypeは2.5倍遅くなりました。null可能でないもののみ-今回は首と首です。
nawfal

しかし、より重要なのは、GetUnderlyingTypenull可能かどうかを確認し、null可能である場合に基になる型を取得する必要がある場合に便利です。これは非常に便利で、のようなパターンがよく見られますActivator.CreateInstance(Nullable.GetUnderlyingType(type) ?? type)。これはasキーワードのようなもので、キャストをチェックし、それを実行して結果を返します。null許容の基になる型を取得したい場合は、GetGenericTypeDefinitionチェックを行ってからジェネリック型を取得することはお勧めできません。またGetUnderlyingType、はるかに読みやすく、覚えやすいです。私がそれを〜1000回だけしているなら、私はそれを気にしません。
nawfal

0

このバージョン:

  • 結果のキャッシュがより速く、
  • Method(T obj)のような不要な変数を必要としません
  • 複雑ではない:)、
  • 一度だけ計算されたフィールドを持つ静的な汎用クラス

public static class IsNullable<T>
{
    private static readonly Type type = typeof(T);
    private static readonly bool is_nullable = type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);
    public static bool Result { get { return is_nullable; } }
}

bool is_nullable = IsNullable<int?>.Result;

静的宣言「is_nullable」で自分に答えたと思います。ヒント:intを使用してオブジェクトを宣言しますか?(オブジェクトa =(int?)8;)そして何が起こるかを見てください。
SoLaR

0

他のすべてが失敗したように見えたので、ここに私が思いついたものがあります-少なくともPLC-Portable Class Library / .NET Core >> C#6

解決策:すべてのタイプのための静的メソッドを拡張TしてNullable<T>、基礎となるタイプに一致する静的な拡張メソッドは、呼び出される予定とジェネリックよりも優先されるという事実を使用T拡張メソッドを。

の場合T

public static partial class ObjectExtension
{
    public static bool IsNullable<T>(this T self)
    {
        return false;
    }
}

そしてのために Nullable<T>

public static partial class NullableExtension
{
    public static bool IsNullable<T>(this Nullable<T> self) where T : struct
    {
        return true;
    }
}

Reflectionおよびtype.IsGenericType...の使用は、現在の.NETランタイムのセットでは機能しませんでした。また、MSDNドキュメントは役に立ちませんでした。

if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) {…}

一部には、.NET CoreでReflection APIが大幅に変更されたためです。


0

Microsoftが推奨するテストを使用するものIsGenericTypeは良いと思いますが、のコードではGetUnderlyingType、Microsoftが追加のテストを使用して、ジェネリック型定義を渡していないことを確認していますNullable<>

 public static bool IsNullableType(this Type nullableType) =>
    // instantiated generic type only                
    nullableType.IsGenericType &&
    !nullableType.IsGenericTypeDefinition &&
    Object.ReferenceEquals(nullableType.GetGenericTypeDefinition(), typeof(Nullable<>));

-1

これを行う簡単な方法:

    public static bool IsNullable(this Type type)
    {
        if (type.IsValueType) return Activator.CreateInstance(type) == null;

        return true;
    }

これらは私のユニットテストであり、すべて合格

    IsNullable_String_ShouldReturn_True
    IsNullable_Boolean_ShouldReturn_False
    IsNullable_Enum_ShouldReturn_Fasle
    IsNullable_Nullable_ShouldReturn_True
    IsNullable_Class_ShouldReturn_True
    IsNullable_Decimal_ShouldReturn_False
    IsNullable_Byte_ShouldReturn_False
    IsNullable_KeyValuePair_ShouldReturn_False

実際の単体テスト

    [TestMethod]
    public void IsNullable_String_ShouldReturn_True()
    {
        var typ = typeof(string);
        var result = typ.IsNullable();
        Assert.IsTrue(result);
    }

    [TestMethod]
    public void IsNullable_Boolean_ShouldReturn_False()
    {
        var typ = typeof(bool);
        var result = typ.IsNullable();
        Assert.IsFalse(result);
    }

    [TestMethod]
    public void IsNullable_Enum_ShouldReturn_Fasle()
    {
        var typ = typeof(System.GenericUriParserOptions);
        var result = typ.IsNullable();
        Assert.IsFalse(result);
    }

    [TestMethod]
    public void IsNullable_Nullable_ShouldReturn_True()
    {
        var typ = typeof(Nullable<bool>);
        var result = typ.IsNullable();
        Assert.IsTrue(result);
    }

    [TestMethod]
    public void IsNullable_Class_ShouldReturn_True()
    {
        var typ = typeof(TestPerson);
        var result = typ.IsNullable();
        Assert.IsTrue(result);
    }

    [TestMethod]
    public void IsNullable_Decimal_ShouldReturn_False()
    {
        var typ = typeof(decimal);
        var result = typ.IsNullable();
        Assert.IsFalse(result);
    }

    [TestMethod]
    public void IsNullable_Byte_ShouldReturn_False()
    {
        var typ = typeof(byte);
        var result = typ.IsNullable();
        Assert.IsFalse(result);
    }

    [TestMethod]
    public void IsNullable_KeyValuePair_ShouldReturn_False()
    {
        var typ = typeof(KeyValuePair<string, string>);
        var result = typ.IsNullable();
        Assert.IsFalse(result);
    }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.