当前位置:  开发笔记 > 编程语言 > 正文

如何检查对象是否可以为空?

如何解决《如何检查对象是否可以为空?》经验,为你挑选了9个好方法。

如何检查给定对象是否可为空,换句话说如何实现以下方法...

bool IsNullableValueType(object o)
{
    ...
}

编辑:我正在寻找可以为空的值类型.我没有记住ref类型.

//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现在指的是type bool(System.Boolean)的对象,其值等于true.我真正想要的是一个类型的对象Nullable

所以现在作为一个解决方法我决定检查o是否可以为空并在obj周围创建一个可空的包装器.



1> Marc Gravell..:

有两种类型的可空 - Nullable和引用类型.

乔恩已经纠正我,如果盒装的话很难获得类型,但是你可以使用泛型: - 所以下面怎么样.这实际上是测试类型T,但是使用obj参数纯粹用于泛型类型推断(以便于调用) - obj尽管如此,它在没有param的情况下几乎完全相同.

static bool IsNullable(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
    return false; // value-type
}

但是如果你已经将值装入对象变量,那么这将不会很好.


最后一行只有在你以某种方式设法得到一个盒装Nullable 而不是直接拳击到T时才有效.这可能,但从我记忆中实现很棘手.
@JustinMorgan如果T是受T:struct约束的通用参数,则不允许T为Nullable <>,因此在这种情况下无需检查!我知道类型`Nullable <>`是一个结构,但是在C#中约束`T:struct`特别排除了可为空的值类型。规范说:_“注意,尽管归为数值类型,但可为空的类型(第4.1.1节)不满足数值类型约束。”

2> Dean Chalk..:

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

http://deanchalk.com/is-it-nullable/

摘抄:

public static class ValueTypeHelper
{
    public static bool IsNullable(T t) { return false; }
    public static bool IsNullable(T? t) where T : struct { return true; }
}

然后

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


您正在检查的**编译时**类型,但它已经是明显的(从智能感知)如果编译时类型为空(`System.Nullable <>`).如果你说`object g = e;`然后`ValueTypeHelper.IsNullable(g)`,你期望获得什么?
我刚刚核实过;**这不起作用**,正如杰普说的那样.如果变量被强制转换为object,它将始终返回false.因此,您无法以这种方式在运行时确定未知对象的类型.唯一可行的方法是在编译时修复类型,在这种情况下,根本不需要运行时检查.
加上一个为您添加测试用例的先生.我已经使用这些测试用例来检查所有其他答案.更多的人应该多加一点.
对于它的价值,这在VB.NET中不起作用.它导致编译器错误"_Overload resolution failed,因为在返回'True`的所有情况下,没有可访问的'IsNullable'对于这些arguments_具有最特殊性".

3> Allon Guraln..:

"如何检查类型是否可以为空"的问题?实际上是"如何检查类型是否Nullable<>?",可以推广为"如何检查类型是否是某种类型的构造类型?",这样它不仅可以回答"是Nullable一个Nullable<>?" 的问题,而且还"是List一个List<>?".

大多数提供的解决方案都使用该Nullable.GetUnderlyingType()方法,这显然只适用于Nullable<>.我没有看到适用于任何通用类型的一般反射解决方案,因此我决定将其添加到后代,即使这个问题早已得到解答.

要检查类型是否是Nullable<>使用反射的某种形式,首先必须将构造的泛型类型Nullable转换为泛型类型定义Nullable<>.您可以使用类的GetGenericTypeDefinition()方法来完成此操作Type.然后,您可以将结果类型与Nullable<>:

Type typeToTest = typeof(Nullable);
bool isNullable = typeToTest.GetGenericTypeDefinition() == typeof(Nullable<>);
// isNullable == true

同样可以应用于任何泛型类型:

Type typeToTest = typeof(List);
bool isList = typeToTest.GetGenericTypeDefinition() == typeof(List<>);
// isList == true

几种类型看起来可能相同,但不同数量的类型参数意味着它是完全不同的类型.

Type typeToTest = typeof(Action);
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();
var listOfStrings = new List();

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

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

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

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



4> Erik..:

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

static bool IsNullable(T obj)
{
    return default(T) == null;
}


对于它的价值,这也是微软使用的测试(http://referencesource.microsoft.com/#mscorlib/system/collections/objectmodel/readonlycollection.cs,219)

5> Jon Skeet..:

好吧,你可以使用:

return !(o is ValueType);

...但是一个对象本身不是可空的,否则 - 一个类型.你打算怎么用这个?


i.GetType()将首先输入到Object,并且没有盒装可空类型 - Nullable 被装箱为空引用或盒装int.
这让我有点失望.例如int?i = 5; typeof(i)返回System.Int32而不是Nullable - typeof(int?)返回Nullable ..我在哪里可以清楚地了解这个主题?
typeof(i)将给出编译器错误 - 您不能将typeof与变量一起使用.你到底做了什么?

6> CARLOS LOTH..:

我能想到的最简单的方法是:

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


我认为这个解决方案是错误的.将Nullable值类型作为参数传递给期望类型为object的参数的方法应该导致装箱发生.Nullable是值类型,装箱转换的结果是引用类型.没有盒装的nullables.我相信这个方法总是返回false?
由于拳击价值,它不起作用.它总是返回FALSE.

7> Mark Jones..:

这里有两个问题:1)测试以查看Type是否可为空; 2)测试一个对象是否代表一个可空类型.

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

对于问题2(测试对象),Dean Chalk上面的解决方案适用于值类型,但它不适用于引用类型,因为使用重载总是返回false.由于引用类型本质上是可空的,因此测试引用类型应始终返回true.有关这些语义的解释,请参阅下面的注释[关于"nullability"].因此,这是我对Dean的方法的修改:

    public static bool IsObjectNullable(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? 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)中修改Dean方法的原因是他的原始方法总是为引用类型返回false.由于像IsObjectNullable这样的方法应该能够处理引用类型值,并且由于所有引用类型本质上都是可空的,因此如果传递了引用类型或null,则该方法应始终返回true.

上述两种方法可以用以下单一方法替换,并实现相同的输出:

    public static bool IsObjectNullable(T obj)
    {
        Type argType = typeof(T);
        if (!argType.IsValueType || obj == null)
            return true;
        return argType.IsGenericType && argType.GetGenericTypeDefinition() == typeof(Nullable<>);
    }

但是,最后一种单方法方法的问题是当使用Nullable 参数时性能会受到影响.执行此单个方法的最后一行所花费的处理器时间比允许编译器在IsObjectNullable调用中使用Nullable -type参数时选择先前显示的第二个方法重载所需的处理器时间长得多.因此,最佳解决方案是使用此处所示的双方法方法.

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

在大多数编码场景中,为了确定可空性,必须依赖于测试原始对象的类型,而不是其参考(例如,代码必须能够访问对象的原始类型以确定可为空性).在这些更常见的情况下,IsTypeNullable(请参阅链接)是确定可为空性的可靠方法.

PS - 关于"可空性"

我应该在一个单独的帖子中重复关于可空性的声明,该声明直接适用于正确解决这个问题.也就是说,我认为这里讨论的重点不应该是如何检查一个对象是否是一个通用的Nullable类型,而是一个人是否可以为其类型的对象赋值null.换句话说,我认为我们应该确定一个对象类型是否可以为空,而不是它是否为Nullable.区别在于语义,即确定可空性的实际原因,这通常都很重要.

在使用类型可能未知的对象直到运行时(Web服务,远程调用,数据库,提要等)的系统中,常见的要求是确定是否可以为对象分配null,或者对象是否可能包含一个null.在非可空类型上执行此类操作可能会产生错误,通常是异常,这在性能和编码要求方面都非常昂贵.为了采取主动避免此类问题的高度优选方法,有必要确定任意类型的对象是否能够包含空值; 即,它是否通常是"可空的".

在一个非常实际和典型的意义上,.NET术语中的可空性并不一定意味着对象的Type是Nullable的一种形式.事实上,在很多情况下,对象具有引用类型,可以包含空值,因此都可以为空; 这些都没有Nullable类型.因此,出于实际目的,在大多数情况下,应该针对可空性的一般概念进行测试,而不是Nullable的依赖于实现的概念.所以我们不应该只关注.NET Nullable类型,而应该在关注可空性的一般实用概念的过程中结合我们对其要求和行为的理解.



8> sclarke81..:

我提出的最简单的解决方案是实现Microsoft的解决方案(如何:识别可空类型(C#编程指南))作为扩展方法:

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

然后可以这样调用:

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

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



9> thinkbeforec..:

在装入可空类型(Nullable例如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))

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

推荐阅读
落单鸟人
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有