我如何检查一个给定的对象是否为空,换句话说,如何实现以下方法…

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周围创建一个可空的包装器。


当前回答

有一个简单的方法:

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

其他回答

有一个使用方法重载的非常简单的解决方案

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

then

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

我认为使用微软对IsGenericType的建议测试是好的,但在GetUnderlyingType的代码中,微软使用了一个额外的测试,以确保你没有通过泛型类型定义Nullable<>:

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

最简单的方法是:

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

nullable有两种类型:nullable <T>和reference-type。

Jon纠正了我,如果是盒装的,很难得到类型,但你可以用泛型: 那么下面呢?这实际上是在测试类型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
}

但是如果你已经将值装箱到一个对象变量中,这就不能很好地工作了。

微软文档:https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/nullable-types/how-to-identify-a-nullable-type

有一个简单的方法:

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