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?

David MZ
źródło
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
Serj-Tm
źródło
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;
}
Siergiej
źródło
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 ....
}
Mike Corcoran
źródło
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;
    }
Seth Reno
źródło
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;
           }

       }
user3359453
źródło
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.

Matas Vaitkevicius
źródło
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;
}
Bruno Marotta
źródło
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")){
    // ...
}
Chtiwi Malek
źródło
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;
    }
Kuroro
źródło
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;
}
Mötz
źródło