检查给定对象(引用或值类型)是否等于其默认值
本文关键字:类型 是否 默认值 于其 对象 引用 检查 | 更新日期: 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();
}
}