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

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


当前回答

“如何检查一个类型是否为空”的问题实际上是“如何检查一个类型是否为nullable <>?”,可以概括为“如何检查一个类型是否为某个泛型类型的构造类型?”,因此它不仅回答了“是否为nullable <int> a nullable <>?”,而且还回答了“是否为List<int> a List<>?”

大多数提供的解决方案使用Nullable. getunderlyingtype()方法,该方法显然只适用于Nullable<>的情况。我没有看到适用于任何泛型类型的一般反射解决方案,所以我决定在这里添加它以供后人使用,尽管这个问题很久以前就已经有了答案。

要使用反射检查类型是否为Nullable<>的某种形式,首先必须将构造的泛型类型(例如Nullable<int>)转换为泛型类型定义Nullable<>。您可以通过使用Type类的GetGenericTypeDefinition()方法来做到这一点。然后你可以将结果类型与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对象对每个类型实例化一次,因此可以检查它们之间的引用是否相等。所以如果你想检查两个对象是否具有相同的泛型类型定义,你可以这样写:

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

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

如果你想检查一个对象是否为空,而不是一个类型,那么你可以使用上面的技术和Marc Gravell的解决方案来创建一个相当简单的方法:

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

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

其他回答

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

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

当装箱一个可空类型(nullable <int> or 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))

它变成了一个真正的引用类型,所以你失去了它是可空的事实。

你可以用:

return !(o is ValueType);

... 但是对象本身不是可空的,而是类型。你打算怎么用这个?

这对我来说很有效,看起来很简单:

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

“如何检查一个类型是否为空”的问题实际上是“如何检查一个类型是否为nullable <>?”,可以概括为“如何检查一个类型是否为某个泛型类型的构造类型?”,因此它不仅回答了“是否为nullable <int> a nullable <>?”,而且还回答了“是否为List<int> a List<>?”

大多数提供的解决方案使用Nullable. getunderlyingtype()方法,该方法显然只适用于Nullable<>的情况。我没有看到适用于任何泛型类型的一般反射解决方案,所以我决定在这里添加它以供后人使用,尽管这个问题很久以前就已经有了答案。

要使用反射检查类型是否为Nullable<>的某种形式,首先必须将构造的泛型类型(例如Nullable<int>)转换为泛型类型定义Nullable<>。您可以通过使用Type类的GetGenericTypeDefinition()方法来做到这一点。然后你可以将结果类型与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对象对每个类型实例化一次,因此可以检查它们之间的引用是否相等。所以如果你想检查两个对象是否具有相同的泛型类型定义,你可以这样写:

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

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

如果你想检查一个对象是否为空,而不是一个类型,那么你可以使用上面的技术和Marc Gravell的解决方案来创建一个相当简单的方法:

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

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