223

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

bool IsNullableValueType(object o)
{
    ...
}

null 許容値型を探しています。私は参照型を念頭に置いていませんでした。

//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は、と等しい値を持つタイプbool( )のオブジェクトを参照するようになりました。私が本当に欲しかったのは型のオブジェクトでしたSystem.BooleantrueNullable<bool>

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

4

14 に答える 14

297

Nullable<T>null 許容型と参照型の 2 種類があります。

Jon は、ボックス化されている場合は型を取得するのが難しいと訂正してくれましたが、ジェネリックを使用すると取得できます。これは実際には typeTをテストしていますが、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

于 2008-12-17T14:20:52.930 に答える
47

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

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
于 2010-11-09T08:50:55.600 に答える
40

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

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);
}
于 2014-04-30T20:52:20.030 に答える
29

「型がnull可能かどうかを確認する方法は?」という質問。は実際には「型が ? であるかどうかを確認する方法Nullable<>」であり、「型がジェネリック型の構築された型であるかどうかを確認する方法は?」に一般化できるため、「?」という質問に答えるだけではありませNullable<int>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オブジェクトはタイプごとに 1 回インスタンス化されるため、それらの間の参照の等価性をチェックできます。したがって、2 つのオブジェクトが同じジェネリック型定義であるかどうかを確認したい場合は、次のように記述できます。

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

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

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

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

    return typeof(T).GetGenericTypeDefinition() == typeof(Nullable<>);
}
于 2011-01-03T11:58:03.667 に答える
20

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

return !(o is ValueType);

...しかし、オブジェクト自体はnull可能ではありません-タイプはそうです。これをどのように使用する予定でしたか?

于 2008-12-17T14:21:45.110 に答える
11

私が理解できる最も簡単な方法は次のとおりです。

public bool IsNullable(object obj)
{
    Type t = obj.GetType();
    return t.IsGenericType 
        && t.GetGenericTypeDefinition() == typeof(Nullable<>);
}
于 2012-03-15T02:10:23.990 に答える
10

ここには 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 可能性の一般的で実用的な概念に注目する必要があります。

于 2011-10-14T00:27:32.057 に答える
10

私が思いついた最も簡単な解決策は、Microsoft のソリューション ( How to: Identify a Nullable Type (C# Programming Guide) ) を拡張メソッドとして実装することです。

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

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

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

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

于 2016-12-22T11:00:36.493 に答える
6

Nullable<int>null 許容型 (または 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 許容であるという事実が失われます。

于 2008-12-17T16:10:04.033 に答える
3

少し話が逸れるかもしれませんが、それでも興味深い情報がいくつかあります。Nullable.GetUnderlyingType() != null型が null 可能であるかどうかを識別するために使用する多くの人を見つけます。これは明らかに機能しますが、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<>): 500ms

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

/// <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();
}
于 2014-07-04T15:32:15.463 に答える
0

他のすべてが失敗したように見えたので、ここに私が思いついたものがあります - 少なくともPLC - Portable Class Library / .NET Core with >= 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<>)) {…}

その理由の 1 つは、Reflection API が .NET Core で大幅に変更されたためです。

于 2016-08-25T06:27:47.337 に答える
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;
于 2015-11-10T20:05:22.583 に答える