2011-07-01 5 views
14

Próbuję znaleźć sposób sprawdzenia i sprawdzić, czy wartość danego obiektu jest równa wartości domyślnej. Mam rozejrzał się i wymyślić to:Sprawdź, czy dany obiekt (typ odniesienia lub wartość) jest równy jego domyślnemu

public static bool IsNullOrDefault<T>(T argument) 
    { 
     if (argument is ValueType || argument != null) 
     { 
      return object.Equals(argument, default(T)); 
     } 
     return true; 
    } 

Problem mam jest, że chcę, aby nazwać tak:

  object o = 0; 
      bool b = Utility.Utility.IsNullOrDefault(o); 

Tak o to obiekt, ale chcę aby ustalić typ bazy i sprawdzić domyślną wartość tego. Typ bazowy, w tym przypadku, jest liczbą całkowitą i chcę wiedzieć w tym przypadku, czy wartość jest równa wartości domyślnej (int), a nie domyślnej (obiekt).

Zaczynam myśleć, że to może nie być możliwe.

+0

Dlaczego nie nazwać jak var o = 0; ? – Jethro

+0

Nie mogę, ponieważ otrzymuję wartość z metody 'GetValue' w' PropertyInfo', która zwraca tylko 'object'. – Brian

+0

możliwy duplikat [Najbardziej skuteczny sposób sprawdzenia, czy obiekt jest typem wartości] (http://stackoverflow.com/questions/5748661/most-efficient-way-to-check-if-an-object-is-a -wartość-typ) – nawfal

Odpowiedz

24

W swojej przykład, całkowita jest zapakowane i dlatego swoje T będzie object, a domyślne obiektu jest zerowy, więc to nie jest cenne dla Ciebie. Jeśli obiekt jest typem wartości, można uzyskać jego instancję (która byłaby domyślna) do użycia jako porównanie. Coś takiego:

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

Chciałbyś poradzić sobie z innymi możliwościami przed ucieczką do tego. Marc Gravell's answer przynosi kilka dobrych punktów do rozważenia, ale dla pełnej wersji swojej metodzie, możesz mieć

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

dobre rozwiązanie problemu. – Keith

+1

Innym sposobem, w jaki można to zaimplementować, jest zakodowanie go jako rozszerzenie: 'publiczny statyczny bool IsNullOrDeafult (ten argument T)' – scottmgerstl

+0

Jak zaznacza Marc Gravell, ale nie dostałem na początku: gdy wartość zerowa jest w pudełku ma wartość zerową lub wartość, typ. Na przykład. \t obiekt o = (int?) 0; \t Debug.Assert (o.GetType() == typeof (int)); // Nie int? Tak, myślę, że to jest mylące zaoferować metoda rodzajowa gdzie: \t IsNullOrDefault - zwraca fałsz, ale \t IsNullOrDefault ((obiekt) (int) 0?) - zwraca true ((int) 0?) (Rzuty nie są rzeczywistymi przypadkami użycia, ale w użytecznych scenariuszach występuje boks.) IMO lepszym rozwiązaniem jest przekazanie w jawnym czasie wykonywania. –

4

jeśli o jest null, w non-generic (object) metody, będziesz miał dostęp do oryginalny typ - i nie można wiele z tym zrobić.

Stąd, tylko raz to się liczy, to nie wartości pustych value-typy, więc:

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

Następujące będzie układać.

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

Rozwijając na odpowiedź Marc Gravell za, dostając typu run-time jako 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); 
} 

Dla tych z was, które będzie wyzwaniem mój przypadek użycia, chcę notować wartości właściwości na dowolnym obiekcie, pomijając właściwości, które ustawiono jako domyślne (dla bardziej zwięzłego wyświetlania).

Ponieważ propertyInfo.GetValue (targetObject, null) zwraca obiekt, a typy wartości są w ramkach, nie mogę użyć metody ogólnej. Przekazując właściwość propertyInfo.PropertyType jako drugi parametr tej metody, mogę uniknąć problemu, jaki ma metoda generyczna dla typów wartości pudełkowych.

0

Złóż metodę rozszerzenia

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