Jak sprawdzić, czy właściwość istnieje w dynamicznym typie anonimowym w języku C #?


122

Mam obiekt typu anonimowego, który otrzymuję jako dynamiczny z metody, którą chciałbym sprawdzić, czy właściwość istnieje w tym obiekcie.

....
var settings = new {
                   Filename="temp.txt",
                   Size=10
}
...

function void Settings(dynamic settings) {
var exists = IsSettingExist(settings,"Filename")
}

Jak zaimplementować IsSettingExist?



Jeśli uważasz, że mocno polegasz na dynamicznych obiektach, prawdopodobnie warto przyjrzeć się F # - Nawiasem mówiąc,
Piotr Kula

Odpowiedzi:


149
  public static bool IsPropertyExist(dynamic settings, string name)
  {
    if (settings is ExpandoObject)
      return ((IDictionary<string, object>)settings).ContainsKey(name);

    return settings.GetType().GetProperty(name) != null;
  }

  var settings = new {Filename = @"c:\temp\q.txt"};
  Console.WriteLine(IsPropertyExist(settings, "Filename"));
  Console.WriteLine(IsPropertyExist(settings, "Size"));

Wynik:

 True
 False

3
To nie działa w przypadku obiektów dynamicznych. Zawsze zwraca wartość null.
evilom

@evilom @Shikasta_Kashti Czy próbujesz użyć tej metody z MVC ViewBag? Jeśli tak, zobacz stackoverflow.com/a/24192518/70345
Ian Kemp

@ Gaspa79. To nierzadka konwencja kodowania. Niektórzy lubią prefiks „Is” we wszystkich właściwościach logicznych. Taka spójność może zapobiec zgadywaniu pierwszych kilku znaków identyfikatora (po czym Intellisense działa), ale kosztem robienia trochę niezręcznego angielskiego w takich przypadkach.
rozpuszczalna ryba

Uważam, że niepoprawny czas czasownika Isprzedrostka jest bardziej zagmatwany, niż byłoby to używane w inny sposób HasProperty. Powiedziałbym również, że używanie niepoprawnego gramatycznie przedrostka, takiego jak ten, nie jest w rzeczywistości idiomatyczne w C♯.
Ben Collins

ExpandoObject to nie to samo, co typ anonimowy. Czy się mylę?
ryanwebjackson

37
public static bool HasProperty(dynamic obj, string name)
{
    Type objType = obj.GetType();

    if (objType == typeof(ExpandoObject))
    {
        return ((IDictionary<string, object>)obj).ContainsKey(name);
    }

    return objType.GetProperty(name) != null;
}

objType.GetProperty(name) != null;zwraca wartość null dla istniejących właściwości
Matas Vaitkevicius

3
objType.GetProperty(name) != nullzawsze zwróci a bool, które (z definicji) nigdy nie może być null.
Alex McMillan,

@AlexMcMillan Nie jestem pewien, w jakim wymiarze mieszkasz, gdzie Type.GetProperty(string)dla nieistniejącej właściwości zwraca cokolwiek innego niż null.
Ian Kemp

2
@IanKemp, AlexMcMillan powiedział objType.GetProperty (name)! = Null w odpowiedzi na komentarz MatasVaitkevicius.
Sergey

15

jeśli możesz kontrolować tworzenie / przekazywanie obiektu ustawień, polecam zamiast tego użycie ExpandoObject.

dynamic settings = new ExpandoObject();
settings.Filename = "asdf.txt";
settings.Size = 10;
...

function void Settings(dynamic settings)
{
    if ( ((IDictionary<string, object>)settings).ContainsKey("Filename") )
        .... do something ....
}

Nie mogę tego zmienić, czy mogę przesyłać do ExpendoObject?
David MZ

6

Działa to dla anonimowych typów ExpandoObject, Nancy.DynamicDictionaryczy cokolwiek innego, co może być oddanych do IDictionary<string, object>.

    public static bool PropertyExists(dynamic obj, string name) {
        if (obj == null) return false;
        if (obj is IDictionary<string, object> dict) {
            return dict.ContainsKey(name);
        }
        return obj.GetType().GetProperty(name) != null;
    }

2
Świetne rozwiązanie. Potrzebowałem dodać jeszcze jedną instrukcję IF podczas konwersji ciągu JSON na JObject .... ”if (obj to Newtonsoft.Json.Linq.JObject) return ((Newtonsoft.Json.Linq.JObject) obj.) .ContainsKey (nazwa); "
rr789

1
Pracował też dla mnie. Wspaniała odpowiedź Seth Reno. Dodałem również "if (obj is Newtonsoft.Json.Linq.JObject) return ((Newtonsoft.Json.Linq.JObject) obj) .ContainsKey (name);" w powyższej funkcji zgodnie z sugestią rr789. Dlatego edytuj swoją odpowiedź, aby ją dołączyć.
Brijesh Kumar Tripathi

1
Dziękuję @BrijeshKumarTripathi! To był dokładnie mój scenariusz.
ryanwebjackson

4

To działa dla mnie-:

  public static bool IsPropertyExist(dynamic dynamicObj, string property)
       {
           try
           {
               var value=dynamicObj[property].Value;
               return true;
           }
           catch (RuntimeBinderException)
           {

               return false;
           }

       }

14
Zezwalanie na występowanie wyjątków, a następnie wyłapywanie ich nie jest preferowanym rozwiązaniem, ponieważ z rzucaniem i łapaniem wiąże się dużo narzutów. To tylko ostateczność. Wyjątki są przeznaczone do sytuacji, które nie powinny mieć miejsca w trakcie wykonywania, na przykład niedostępność sieci. Są tutaj znacznie lepsze rozwiązania.
Cokolwiek Man

Nie powiedzie się RuntimeBinderException, a dynamicObj[property].Value gdy wartość jest rzeczywiście istnieje ... var value = dynamicObj[property]wystarczy ... a gdy go nie ma KeyNotFoundException na Dictionaryto rzucony ... patrz niżej ...
Matas Vaitkevicius

Używanie wyjątków w logice biznesowej jest niedopuszczalnym rozwiązaniem. I stopień, II semestr.
Artem G

3

Żadne z powyższych rozwiązań pracował dynamic, która pochodzi od Json, ja jednak udało się przekształcić jeden z Try catch(przez @ user3359453) zmieniając typ wyjątku rzucony ( KeyNotFoundExceptionzamiast RuntimeBinderException) w coś, co faktycznie działa ...

public static bool HasProperty(dynamic obj, string name)
    {
        try
        {
            var value = obj[name];
            return true;
        }
        catch (KeyNotFoundException)
        {
            return false;
        }
    }

wprowadź opis obrazu tutaj

Mam nadzieję, że zaoszczędzi ci to trochę czasu.


1
Używanie wyjątków do takich rzeczy nie jest zalecane. ! Należy odeszłaś czegoś jak odlewania do JObject i korzystania .Property () = null
Gaspa79

3

Scalanie i naprawianie odpowiedzi od Serj-TM i user3359453, tak aby działało zarówno z ExpandoObject, jak i DynamicJsonObject. To działa dla mnie.

public static bool HasPropertyExist(dynamic settings, string name)
{
    if (settings is System.Dynamic.ExpandoObject)
        return ((IDictionary<string, object>)settings).ContainsKey(name);

    if (settings is System.Web.Helpers.DynamicJsonObject)
    try
    {
        return settings[name] != null;
    }
    catch (KeyNotFoundException)
    {
        return false;
    }


    return settings.GetType().GetProperty(name) != null;
}

2

Używając refleksji, to jest funkcja, której używam:

public static bool doesPropertyExist(dynamic obj, string property)
{
    return ((Type)obj.GetType()).GetProperties().Where(p => p.Name.Equals(property)).Any();
}

następnie..

if (doesPropertyExist(myDynamicObject, "myProperty")){
    // ...
}

2
GetProperties () nie wyświetla dynamicznego elementu członkowskiego w obiekcie DynamicObject. Jest do tego dedykowana funkcja GetDynamicMemberNames ().
Marco Guignard

Użycie Wherenajpierw wyrażenia lambda , a następnie Anyjest zbędne, ponieważ można również sformułować wyrażenie filtrujące w programie Any.
pholpar

1

W przypadku, gdy ktoś musi obsłużyć obiekt dynamiczny pochodzący z Json, zmodyfikowałem odpowiedź Setha Reno, aby obsłużyć obiekt dynamiczny zdeserializowany z NewtonSoft.Json.JObjcet.

public static bool PropertyExists(dynamic obj, string name)
    {
        if (obj == null) return false;
        if (obj is ExpandoObject)
            return ((IDictionary<string, object>)obj).ContainsKey(name);
        if (obj is IDictionary<string, object> dict1)
            return dict1.ContainsKey(name);
        if (obj is IDictionary<string, JToken> dict2)
            return dict2.ContainsKey(name);
        return obj.GetType().GetProperty(name) != null;
    }

0

Aby przedłużyć odpowiedź z @Kuroro, jeśli chcesz sprawdzić, czy właściwość jest pusta, poniżej powinno działać.

public static bool PropertyExistsAndIsNotNull(dynamic obj, string name)
{
    if (obj == null) return false;
    if (obj is ExpandoObject)
    {
        if (((IDictionary<string, object>)obj).ContainsKey(name))
            return ((IDictionary<string, object>)obj)[name] != null;
        return false;
    }
    if (obj is IDictionary<string, object> dict1)
    {
        if (dict1.ContainsKey(name))
            return dict1[name] != null;
        return false;
    }
    if (obj is IDictionary<string, JToken> dict2)
    {
        if (dict2.ContainsKey(name))
            return (dict2[name].Type != JTokenType.Null && dict2[name].Type != JTokenType.Undefined);
        return false;
    }
    if (obj.GetType().GetProperty(name) != null)
        return obj.GetType().GetProperty(name).GetValue(obj) != null;
    return false;
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.