检查给定对象(引用或值类型)是不是等于其默认值

Posted

技术标签:

【中文标题】检查给定对象(引用或值类型)是不是等于其默认值【英文标题】:Check to see if a given object (reference or value type) is equal to its default检查给定对象(引用或值类型)是否等于其默认值 【发布时间】:2011-09-27 01:07:21 【问题描述】:

我正在尝试找到一种方法来检查给定对象的值是否等于其默认值。我环顾四周,想出了这个:

    public static bool IsNullOrDefault<T>(T argument)
    
        if (argument is ValueType || argument != null)
        
            return object.Equals(argument, default(T));
        
        return true;
    

我遇到的问题是我想这样称呼它:

            object o = 0;
            bool b = Utility.Utility.IsNullOrDefault(o);

是的 o 是一个对象,但我想让它找出基本类型并检查它的默认值。在这种情况下,基本类型是一个整数,我想知道在这种情况下该值是否等于 default(int),而不是 default(object)。

我开始认为这可能是不可能的。

【问题讨论】:

为什么不把它叫做 var o = 0; ? 我不能,因为我从PropertyInfo 中的GetValue 方法获取值,它只返回一个object Most efficient way to check if an object is a value type 的可能重复项 【参考方案1】:

在您的示例中,您的整数被装箱,因此您的 T 将是 object,并且 object 的默认值为 null,因此这对您没有价值。如果对象是值类型,您可以获得它的一个实例(这将是默认值)以用作比较。类似的东西:

if (argument is ValueType)

   object obj = Activator.CreateInstance(argument.GetType());
   return obj.Equals(argument);

在诉诸此方法之前,您需要处理其他可能性。 Marc Gravell's answer 提出了一些需要考虑的好点,但是对于您的方法的完整版本,您可能有

public static bool IsNullOrDefault<T>(T argument)

    // deal with normal scenarios
    if (argument == null) return true;
    if (object.Equals(argument, default(T))) return true;

    // deal with non-null nullables
    Type methodType = typeof(T);
    if (Nullable.GetUnderlyingType(methodType) != null) return false;

    // deal with boxed value types
    Type argumentType = argument.GetType();
    if (argumentType.IsValueType && argumentType != methodType) 
    
        object obj = Activator.CreateInstance(argument.GetType());
        return obj.Equals(argument);
    

    return false;

【讨论】:

实现此功能的另一种方法是将其编码为扩展:public static bool IsNullOrDeafult&lt;T&gt;(this T argument) 正如 Marc Gravell 指出的那样,但我一开始并没有得到:当一个可空值被装箱时,它要么是空值,要么是值,类型。例如。对象 o = (int?) 0; Debug.Assert(o.GetType() == typeof(int)); // 不是整数?所以,我认为提供一个通用方法是误导: IsNullOrDefault((int?) 0) - 返回 false,但 IsNullOrDefault((object) (int?) 0) - 返回 true (强制转换不是真正的用途情况下,但在有用的场景中确实会发生装箱。)IMO 更好的解决方案是传入显式运行时类型。【参考方案2】:

如果 o 为 null,则在非泛型 (object) 方法中,您将无法访问原始类型 - 您对此无能为力。

因此,唯一重要的是不可为空的值类型,所以:

Type type = value.GetType();
if(!type.IsValueType) return false; // can't be, as would be null
if(Nullable.GetUnderlyingType(type) != null) return false; // ditto, Nullable<T>
object defaultValue = Activator.CreateInstance(type); // must exist for structs
return value.Equals(defaultValue);

【讨论】:

【参考方案3】:

将Anthony Pegram's Answer转换为扩展方法:

using System;

//Adapted from https://***.com/a/6553276/1889720
public static class ObjectExtensions

    public static bool IsNullOrDefault<TObject>(this TObject argument)
    
        // deal with normal scenarios
        if (argument == null)
        
            return true;
        
        if (object.Equals(argument, default(TObject)))
        
            return true;
        

        // deal with non-null nullables
        Type methodType = typeof(TObject);
        if (Nullable.GetUnderlyingType(methodType) != null)
        
            return false;
        

        // deal with boxed value types
        Type argumentType = argument.GetType();
        if (argumentType.IsValueType && argumentType != methodType)
        
            object obj = Activator.CreateInstance(argument.GetType());
            return obj.Equals(argument);
        

        return false;
    

使用语法:

myVariable.IsNullOrDefault();

【讨论】:

【参考方案4】:

通过将运行时类型作为参数扩展 Marc Gravell 的答案:

// Handles boxed value types
public static bool IsNullOrDefault([CanBeNull] this object @object,
    [NotNull] Type runtimeType)

    if (@object == null) return true;

    if (runtimeType == null) throw new ArgumentNullException("runtimeType");

    // Handle non-null reference types.
    if (!runtimeType.IsValueType) return false;

    // Nullable, but not null
    if (Nullable.GetUnderlyingType(runtimeType) != null) return false;

    // Use CreateInstance as the most reliable way to get default value for a value type
    object defaultValue = Activator.CreateInstance(runtimeType);

    return defaultValue.Equals(@object);

对于那些将挑战我的用例的人,我想列出任意对象的属性值,省略设置为默认值的属性(为了更简洁的显示)。

因为 propertyInfo.GetValue(targetObject, null) 返回一个对象,并且值类型被装箱,所以我不能使用泛型方法。通过将 propertyInfo.PropertyType 作为第二个参数传递给该方法,我可以避免泛型方法对装箱值类型的问题。

【讨论】:

表达得很好。我有一个非常相似的用例。不幸的是,C# 使用对象作为基本类型,然后是泛型类型,然后是可空类型的演变方式,像value == default(type) 这样的简单检查必须以如此详尽的细节表达。谢谢【参考方案5】:

下面会整理出来。

    public static bool IsNullOrDefault<T>(T argument)

    if (argument is ValueType || argument != null)
    
        return object.Equals(argument, GetDefault(argument.GetType()));
    
    return true;



public static object GetDefault(Type type)

    if(type.IsValueType)
    
        return Activator.CreateInstance(type);
    
    return null;

【讨论】:

【参考方案6】:

制作扩展方法

 public static class DateExtension

    public static bool IsNullOrDefault(this DateTime? value)
    
        return default(DateTime) == value || default(DateTime?) == value;
    

【讨论】:

【参考方案7】:

使用 linq 表达式的解决方案。第一次调用 type 会比较慢,但它应该和通常的代码一样快。

public static class DefaultHelper

    private delegate bool IsDefaultValueDelegate(object value);

    private static readonly ConcurrentDictionary<Type, IsDefaultValueDelegate> Delegates
        = new ConcurrentDictionary<Type, IsDefaultValueDelegate>();

    public static bool IsDefaultValue(this object value)
    
        var type = value.GetType();
        var isDefaultDelegate = Delegates.GetOrAdd(type, CreateDelegate);
        return isDefaultDelegate(value);
    

    private static IsDefaultValueDelegate CreateDelegate(Type type)
    
        var parameter = Expression.Parameter(typeof(object));
        var expression = Expression.Equal(
            Expression.Convert(parameter, type),
            Expression.Default(type));
        return Expression.Lambda<IsDefaultValueDelegate>(expression, parameter).Compile();
    

【讨论】:

您可以简单地将默认值存储在字典中并进行比较,而不是创建表达式。

以上是关于检查给定对象(引用或值类型)是不是等于其默认值的主要内容,如果未能解决你的问题,请参考以下文章

fluentvalidation

JAVA中初始化及默认值,包装类与基本类型

我可以检查散列密码是不是等于 laravel 中的特定值?

Javascript 是不是通过引用或值将数组传递给函数?

关于java中属性变量默认值的问题。

如何通过引用或值返回智能指针(shared_ptr)?