Как проверить, является ли объект обнуляемым? - PullRequest
186 голосов
/ 17 декабря 2008

Как проверить, можно ли обнулить данный объект другими словами, как реализовать следующий метод ...

bool IsNullableValueType(object o)
{
    ...
}

РЕДАКТИРОВАТЬ: Я ищу типы значений обнуляемый. Я не имел в виду типы ссылок.

//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.Boolean) со значением, равным true. Что я действительно хотел, так это объект типа Nullable<bool>

Так что теперь в качестве обходного пути я решил проверить, может ли o быть обнуляемым, и создать обнуляемую оболочку вокруг obj.

Ответы [ 14 ]

0 голосов
/ 21 января 2019

Я думаю, что те, которые используют предложенное 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<>));
0 голосов
/ 25 августа 2016

Вот то, что я придумал, так как все остальное казалось неудачным - по крайней мере на 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 Runtime. Также не помогла Документация MSDN .

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

Частично потому, что API-интерфейс Reflection значительно изменился в .NET Core.

0 голосов
/ 10 ноября 2015

Эта версия:

  • результаты кеширования быстрее,
  • не требует ненужных переменных, таких как 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;
0 голосов
/ 18 августа 2015

простой способ сделать это:

    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);
    }
...