Проверьте, равен ли данный объект (ссылка или тип значения) его значению по умолчанию - PullRequest
21 голосов
/ 02 июля 2011

Я пытаюсь найти способ проверить и проверить, равно ли значение данного объекта его значению по умолчанию.Я огляделся и придумал следующее:

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

Я начинаю думать, что это можетне возможно.

Ответы [ 7 ]

30 голосов
/ 02 июля 2011

В вашем примере ваше целое число в штучной упаковке, и поэтому ваш T будет object, а значение по умолчанию для объекта равно нулю, так что это не имеет значения для вас. Если объект является типом значения, вы можете получить его экземпляр (который будет использоваться по умолчанию) для использования в качестве сравнения. Что-то вроде:

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

Вы хотели бы иметь дело с другими возможностями, прежде чем прибегать к этому. Ответ Марка Гравелла приводит несколько хороших моментов для рассмотрения, но для полной версии вашего метода у вас может быть

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;
}
6 голосов
/ 02 июля 2011

если o равно нулю, в неуниверсальном (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);
2 голосов
/ 20 ноября 2015

Расширяя ответ Марка Гравелла, получая в качестве аргумента тип времени выполнения:

// 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 в качестве второго параметра этому методу, я могу избежать проблемы, которую универсальный метод имеет с типами в штучной упаковке.

1 голос
/ 24 мая 2018

Преобразовано Ответ Энтони Пеграма в метод расширения:

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();
1 голос
/ 02 июля 2011

Следующая разберется.

    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;
}
0 голосов
/ 05 июля 2018

Решение с выражениями 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();
    }
}
0 голосов
/ 22 июня 2017

Сделать метод расширения

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