Check to see if a given object (reference or value type) is equal to its default
Solution 1
In your example, your integer is boxed and therefore your T
is going to be object
, and the default of object is null, so that's not valuable to you. If the object is a value type, you could get an instance of it (which would be the default) to use as a comparison. Something like:
if (argument is ValueType)
{
object obj = Activator.CreateInstance(argument.GetType());
return obj.Equals(argument);
}
You'd want to deal with other possibilities before resorting to this. Marc Gravell's answer brings up some good points to consider, but for a full version of your method, you might have
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;
}
Solution 2
if o
is null, in a non-generic (object
) method, you will have no access to the original type - and you can't do much about that.
Hence, the only time it matters is non-nullable value-types, so:
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);
Solution 3
Converted Anthony Pegram's Answer into an extension method:
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;
}
}
Usage syntax:
myVariable.IsNullOrDefault();
Solution 4
Expanding on Marc Gravell's answer, by getting the run-time type as an argument:
// 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);
}
For those of you that will challenge my use case, I want to list the values of properties on an arbitrary object, omitting properties which set to their defaults (for a more concise display).
Because propertyInfo.GetValue(targetObject, null) returns an object, and value types are boxed, I cannot use a generic method. By passing propertyInfo.PropertyType as the second parameter to this method I can avoid the problem a generic method has with boxed value types.
Solution 5
The following will sort it out.
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;
}
Brian
Updated on June 13, 2022Comments
-
Brian about 2 years
I'm trying to find a way to check and see if the value of a given object is equal to its default value. I've looked around and come up with this:
public static bool IsNullOrDefault<T>(T argument) { if (argument is ValueType || argument != null) { return object.Equals(argument, default(T)); } return true; }
The problem I'm having is that I want to call it like this:
object o = 0; bool b = Utility.Utility.IsNullOrDefault(o);
Yes o is an object, but I want to make it figure out the base type and check the default value of that. The base type, in this case, is an integer and I want to know in this case if the value is equal to default(int), not default(object).
I'm starting to think this might not be possible.