web-dev-qa-db-ja.com

リフレクションによるNullable型の検出

驚くべきことに、次のコードはアサートに失敗します。

int? wtf = 0;
Assert.IsType<Nullable<int>>(wtf);

では、好奇心から、特定のインスタンスがNullable <>オブジェクトであるかどうかをどのように判断できますか?

24
justin.m.chase

まず、_Nullable<T>_は構造体であるため、object自体はありません。 GetType()を呼び出すことはできません。これは、値をボックス化するためです(この時点で、nullを取得して例外を取得するか、ボックス化されたnull不可能な値を取得して必要なタイプを取得しません)。

(ボクシングはここであなたの主張を台無しにしているものです-私はIsTypeobjectを受け入れると思います。)

ただし、型推論を使用して、変数の型を型パラメーターとして取得できます。

_public bool IsNullable<T>(T value)
{
    return Nullable.GetUnderlyingType(typeof(T)) != null;
}
_

例のようにコンパイル時に正確な型がわかっている場合、これはそれほど多くは使用されませんが、ジェネリックスには役立ちます。 (もちろん、それを実装する別の方法があります。)

あなたの実際の状況はどうですか?コンパイル時にこれに対する答えを知っていることを考えると、これはこのようなアサーションではないと思います。

58
Jon Skeet

@ jon-skeetの回答が好きですが、テスト対象のタイプがわかっている場合にのみ機能します。私たちの世界では、リフレクションを使用してオブジェクトを開き、正規表現に対して値をテストしています。

あらゆるタイプで機能するように拡張機能を単純化することは、私たちにとってより効果的でした。

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

ジェネリックは生命の血ですが、時々... :)

4
hal9000
int? i = 0;
var type = TypedReference.GetTargetType(__makeref(i));
var isNullable = type.IsGenericType &&
    type.GetGenericTypeDefinition() == typeof(Nullable<>);
3
Vladimir

これが私が思いついたものです。他のすべてが失敗したように見えたので、少なくともポータブルクラスライブラリ/DotNet Core with> = C#6

基本的に、ジェネリック型Objectと_Nullable<T>_を拡張し、基になる型に一致する静的拡張メソッドが呼び出され、ジェネリックT拡張よりも優先されるという事実を使用します-方法。

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

1つは_Nullable<T>_用です

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

Reflectionと_type.IsGeneric_およびtype.GetGenericParameters()の使用は、現在の.NETランタイムのセットでは機能しませんでした。

0
Lorenz Lo Sauer

Assertはどの名前空間にありますか?

以下は、予想どおりtrueを返します。

_int? wtf = 0;
if (typeof(Nullable<int>).IsInstanceOfType(wtf))
{
    // Do things
}
_

typeof(Nullable<int>).IsInstanceOfType(42)もtrueを返すことに注意してください。これは、このメソッドがobjectを受け入れるため、_Nullable<int>_としてボックス化されるためです。

0
Justin