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

本文关键字:类型 是否 默认值 于其 对象 引用 检查 | 更新日期: 2023-09-27 18:00:59

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

    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(。

我开始觉得这可能是不可能的。

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

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

if (argument is ValueType)
{
   object obj = Activator.CreateInstance(argument.GetType());
   return obj.Equals(argument);
}

在诉诸于此之前,您可能需要处理其他可能性。Marc Gravell的回答提出了一些值得考虑的要点,但对于你的方法的完整版本,你可能有

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

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

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

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

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

using System;
//Adapted from https://stackoverflow.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();

通过获取运行时类型作为参数来扩展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作为第二个参数传递给该方法,我可以避免泛型方法中装箱值类型的问题。

下面将对其进行排序。

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

制作一个扩展方法

 public static class DateExtension
{
    public static bool IsNullOrDefault(this DateTime? value)
    {
        return default(DateTime) == value || default(DateTime?) == value;
    }
}

使用linq表达式的解决方案。对类型的第一次调用将相对较慢,但随后它应该和通常的代码一样快。

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