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

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


当前回答

这个版本:

缓存结果更快, 不需要不必要的变量,如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;

其他回答

我想到的最简单的解决方案是实现微软的解决方案(如何:识别可空类型(c#编程指南))作为扩展方法:

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

然后可以这样调用:

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

这似乎也是访问IsNullable()的一种逻辑方式,因为它适合Type类的所有其他IsXxxx()方法。

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

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

这里有两个问题:1)测试一个类型是否为空;以及2)测试一个对象是否代表一个可空的类型。

对于问题1(测试类型),这里是我在自己的系统中使用的解决方案:typeisnulable -检查解决方案

对于问题2(测试对象),Dean Chalk的上述解决方案适用于值类型,但不适用于引用类型,因为使用<T>重载总是返回false。由于引用类型本质上是可空的,因此测试引用类型应该总是返回true。关于这些语义的解释,请参阅下面的注释[关于“可空性”]。因此,以下是我对Dean方法的修改:

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

下面是我对上述解决方案的客户端测试代码的修改:

    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这样的方法应该能够处理引用类型的值,而且所有的引用类型本质上都是可空的,那么如果传递的是引用类型或空值,该方法应该总是返回true。

以上两种方法可以用以下单一方法代替,得到相同的输出:

    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>类型参数时,执行这个方法的最后一行所花费的处理器时间要比允许编译器选择前面所示的第二个方法重载所花费的处理器时间多得多。因此,最佳解决方案是使用这里所示的两种方法。

注意:此方法只有在使用原始对象引用或精确副本调用时才能可靠地工作,如示例所示。但是,如果一个可空对象被装箱为另一个类型(如object等),而不是保持其原始的nullable <>形式,则此方法将不可靠地工作。如果调用此方法的代码没有使用原始的、未装箱的对象引用或精确的副本,则不能使用此方法可靠地确定对象的可空性。

在大多数编码场景中,要确定可空性,必须依赖于测试原始对象的Type,而不是它的引用(例如,代码必须访问对象的原始Type才能确定可空性)。在这些更常见的情况下,IsTypeNullable(见链接)是确定可空性的可靠方法。

附注:关于“可空性”

I should repeat a statement about nullability I made in a separate post, which applies directly to properly addressing this topic. That is, I believe the focus of the discussion here should not be how to check to see if an object is a generic Nullable type, but rather whether one can assign a value of null to an object of its type. In other words, I think we should be determining whether an object type is nullable, not whether it is Nullable. The difference is in semantics, namely the practical reasons for determining nullability, which is usually all that matters.

In a system using objects with types possibly unknown until run-time (web services, remote calls, databases, feeds, etc.), a common requirement is to determine whether a null can be assigned to the object, or whether the object might contain a null. Performing such operations on non-nullable types will likely produce errors, usually exceptions, which are very expensive both in terms of performance and coding requirements. To take the highly-preferred approach of proactively avoiding such problems, it is necessary to determine whether an object of an arbitrary Type is capable of containing a null; i.e., whether it is generally 'nullable'.

In a very practical and typical sense, nullability in .NET terms does not at all necessarily imply that an object's Type is a form of Nullable. In many cases in fact, objects have reference types, can contain a null value, and thus are all nullable; none of these have a Nullable type. Therefore, for practical purposes in most scenarios, testing should be done for the general concept of nullability, vs. the implementation-dependent concept of Nullable. So we should not be hung up by focusing solely on the .NET Nullable type but rather incorporate our understanding of its requirements and behavior in the process of focusing on the general, practical concept of nullability.

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

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

最简单的方法是:

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