检查给定对象(引用或值类型)是不是等于其默认值
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<T>(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();
【讨论】:
您可以简单地将默认值存储在字典中并进行比较,而不是创建表达式。以上是关于检查给定对象(引用或值类型)是不是等于其默认值的主要内容,如果未能解决你的问题,请参考以下文章