Wie überprüfe ich, ob eine Eigenschaft für einen dynamischen anonymen Typ in c # vorhanden ist?

121

Ich habe ein anonymes Typobjekt, das ich als Dynamik von einer Methode erhalte, die ich überprüfen möchte, ob eine Eigenschaft für dieses Objekt vorhanden ist.

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

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

Wie würde ich IsSettingExist implementieren?

David MZ
quelle
Wenn Sie sich stark auf dynamische Objekte verlassen, lohnt es sich wahrscheinlich, sich F # - Nice Avatar übrigens
Piotr Kula

Antworten:

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

Ausgabe:

 True
 False
Serj-Tm
quelle
2
Dies funktioniert nicht bei dynamischen Objekten. Es wird immer null zurückgegeben.
böse
@evilom @Shikasta_Kashti Versuchen Sie, diese Methode mit einer MVC zu verwenden ViewBag? Wenn ja, siehe stackoverflow.com/a/24192518/70345
Ian Kemp
7
Echte Frage: Warum IsPropertyExist anstelle von DoesPropertyExist / HasProperty? Ist es eine Konvention, die ich nicht verstehe?
Gaspa79
@ Gaspa79. Es ist eine nicht ungewöhnliche Codierungskonvention. Einige Leute mögen ein "Is" -Präfix für alle booleschen Eigenschaften. Eine solche Konsistenz kann verhindern, dass Sie die ersten Zeichen eines Bezeichners erraten müssen (danach funktioniert Intellisense), in solchen Fällen jedoch auf Kosten eines etwas umständlichen Englisch.
löslicher Fisch
Ich finde die ungültige Verbform des IsPräfixes verwirrender, als es sonst zu verwenden wäre HasProperty. Ich würde auch sagen, dass die Verwendung eines solchen grammatikalisch falschen Präfixes in C♯ eigentlich nicht idiomatisch ist.
Ben Collins
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;
}
Sergey
quelle
objType.GetProperty(name) != null;gibt null für Eigenschaften zurück, die existieren
Matas Vaitkevicius
3
objType.GetProperty(name) != nullwird immer ein zurückgeben bool, was (per Definition) niemals sein kann null.
Alex McMillan
@AlexMcMillan Sie sind sich nicht sicher, in welcher Dimension Sie wo Type.GetProperty(string)für eine nicht vorhandene Eigenschaft leben, und geben etwas anderes als null zurück.
Ian Kemp
2
@ IanKemp, AlexMcMillan sagte objType.GetProperty (Name)! = Null als Antwort auf MatasVaitkevicius Kommentar tatsächlich.
Sergey
15

Wenn Sie das Erstellen / Übergeben des Einstellungsobjekts steuern können, würde ich empfehlen, stattdessen ein ExpandoObject zu verwenden.

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
quelle
Ich kann es nicht ändern. Kann ich es auf ExpendoObject übertragen?
David MZ
6

Dies funktioniert für anonyme Typen, ExpandoObject, Nancy.DynamicDictionaryoder irgendetwas anderes, das gegossen werden kann 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
quelle
2
Tolle Lösung. Ich musste eine weitere IF-Anweisung hinzufügen, wenn ich eine JSON-Zeichenfolge in JObject konvertierte .... "if (obj ist Newtonsoft.Json.Linq.JObject) return ((Newtonsoft.Json.Linq.JObject) obj) .ContainsKey (name); ""
rr789
Arbeitete auch für mich. Wunderbare Antwort Seth Reno. Ich habe auch hinzugefügt "if (obj ist Newtonsoft.Json.Linq.JObject) return ((Newtonsoft.Json.Linq.JObject) obj) .ContainsKey (name);" in der obigen Funktion wie von rr789 vorgeschlagen. Bearbeiten Sie daher auch Ihre Antwort, um sie einzuschließen.
Brijesh Kumar Tripathi
4

Das funktioniert bei mir-:

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

               return false;
           }

       }
user3359453
quelle
13
Es ist keine bevorzugte Lösung, Ausnahmen zuzulassen und sie dann zu fangen, da mit dem Werfen und Fangen viel Aufwand verbunden ist. Es ist nur ein letzter Ausweg. Ausnahmen sind für für Situationen entwickelt, sollte nicht im Laufe der Ausführung wie ein Netzwerk nicht verfügbar ist geschehen. Hier gibt es viel bessere Lösungen.
Was auch immer Mann
Schlägt mit RuntimeBinderExceptionund dynamicObj[property].Value wenn der Wert tatsächlich gibt es ... var value = dynamicObj[property]ist genug ... und wenn es nicht vorhanden ist KeyNotFoundException aufDictionary geworfen wird ... siehe unten ...
Matas Vaitkevicius
Es ist keine akzeptable Lösung, Ausnahmen in der Geschäftslogik zu verwenden. 1 Klasse, 2. Semester.
Artem G
3

Keine der oben genannten Lösungen gearbeitet , dynamicdass kommt von Json, ich aber eines mit zu transformieren verwaltet Try catch(von @ user3359453) durch Ausnahmetyp (geworfen Wechsel KeyNotFoundExceptionstatt RuntimeBinderException) in etwas , das tatsächlich funktioniert ...

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

Geben Sie hier die Bildbeschreibung ein

Hoffe das spart dir etwas Zeit.

Matas Vaitkevicius
quelle
1
Die Verwendung von Ausnahmen für solche Dinge wird nicht empfohlen. Hätte etwas wie Casting für JObject und Verwendung von .Property ()! = Null
Gaspa79
3

Zusammenführen und Korrigieren von Antworten von Serj-TM und user3359453, sodass es sowohl mit ExpandoObject als auch mit DynamicJsonObject funktioniert. Das funktioniert bei mir.

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
quelle
2

Mit Reflektion ist dies die Funktion, die ich benutze:

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

dann..

if (doesPropertyExist(myDynamicObject, "myProperty")){
    // ...
}
Chtiwi Malek
quelle
1
GetProperties () listet kein dynamisches Mitglied in einem DynamicObject auf. Dafür gibt es eine spezielle Funktion GetDynamicMemberNames ().
Marco Guignard
Verwenden Sie zuerst den Lambda-Ausdruck Whereund dann Anyist er redundant, da Sie auch Ihren Filterausdruck in formulieren können Any.
Pholpar
1

Für den Fall, dass jemand ein dynamisches Objekt von Json verarbeiten muss, habe ich die Antwort von Seth Reno geändert, um dynamische Objekte zu verarbeiten, die von NewtonSoft.Json.JObjcet deserialisiert wurden.

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
quelle
0

Um die Antwort von @Kuroro zu erweitern, sollte unten funktionieren, wenn Sie testen müssen, ob die Eigenschaft leer ist.

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
quelle