Come posso verificare se esiste una proprietà su un tipo anonimo dinamico in c #?


122

Ho un oggetto di tipo anonimo che ricevo come dinamico da un metodo che vorrei controllare in una proprietà esistente su quell'oggetto.

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

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

Come implementerei IsSettingExist?



Se ti accorgi che il tuo io fa molto affidamento su oggetti dinamici, probabilmente vale la pena guardare F # - Nice Avatar a proposito
Piotr Kula

Risposte:


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

Produzione:

 True
 False

3
Questo non funziona sugli oggetti dinamici. Restituisce sempre null.
evilom

@evilom @Shikasta_Kashti Stai cercando di utilizzare questo metodo con un MVC ViewBag? In tal caso, vedere stackoverflow.com/a/24192518/70345
Ian Kemp

@ Gaspa79. È una convenzione di codifica non insolita. Ad alcune persone piace un prefisso "È" su tutte le proprietà booleane. Una tale coerenza può impedirti di dover indovinare i primi caratteri di un identificatore (dopodiché, Intellisense funziona), ma a scapito di fare un po 'di goffo inglese in casi come questo.
solublefish

Trovo che il tempo verbale non valido del Isprefisso sia più confuso di quanto sarebbe altrimenti da usare HasProperty. Direi anche che usare un prefisso grammaticalmente errato come questo è in realtà non idiomatico in C♯.
Ben Collins

ExpandoObject non è la stessa cosa del tipo anonimo. Mi sbaglio su questo?
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;restituisce null sulle proprietà che esistono
Matas Vaitkevicius

3
objType.GetProperty(name) != nullrestituirà sempre a bool, che (per definizione) non può mai essere null.
Alex McMillan

@AlexMcMillan Non sei sicuro della dimensione in cui vivi e dove Type.GetProperty(string)una proprietà inesistente restituisce qualcosa di diverso da null.
Ian Kemp

2
@IanKemp, AlexMcMillan ha detto objType.GetProperty (name)! = Null in risposta al commento di MatasVaitkevicius in realtà.
Sergey

15

se puoi controllare la creazione / il passaggio dell'oggetto impostazioni, ti consiglio di utilizzare invece un 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 ....
}

Non posso cambiarlo, posso trasmettere a ExpendoObject?
David MZ

6

Questo funziona per i tipi anonimi, ExpandoObject, Nancy.DynamicDictionaryo qualsiasi altra cosa che possono essere espressi a 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
Ottima soluzione. Avevo bisogno di aggiungere un'altra istruzione IF durante la conversione della stringa JSON in JObject .... "if (obj is Newtonsoft.Json.Linq.JObject) return ((Newtonsoft.Json.Linq.JObject) obj) .ContainsKey (name); "
rr789

1
Ha funzionato anche per me. Splendida risposta Seth Reno. Ho anche aggiunto "if (obj is Newtonsoft.Json.Linq.JObject) return ((Newtonsoft.Json.Linq.JObject) obj) .ContainsKey (name);" nella funzione sopra come suggerito da rr789. Quindi modifica anche la tua risposta per includerla.
Brijesh Kumar Tripathi

1
Grazie @BrijeshKumarTripathi! Questo era esattamente il mio scenario.
ryanwebjackson

4

Questo sta funzionando per me-:

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

               return false;
           }

       }

14
Consentire il verificarsi di eccezioni e poi catturarle non è una soluzione preferita perché ci sono molte spese generali associate a lancio e cattura. È solo l'ultima risorsa. Le eccezioni sono progettate per situazioni che non dovrebbero verificarsi nel corso dell'esecuzione, come una rete non disponibile. Ci sono soluzioni molto migliori qui.
Qualunque uomo

Fallisce con RuntimeBinderExceptione dynamicObj[property].Value quando il valore è in realtà c'è ... var value = dynamicObj[property]basta ... e quando non esiste KeyNotFoundException su Dictionaryè gettato ... vedi sotto ...
Matas Vaitkevicius

Non è una soluzione accettabile utilizzare le eccezioni nella logica aziendale. 1 grado, 2 ° trimestre.
Artem G

3

Nessuna delle soluzioni sopra ha funzionato da dynamiccui proviene Json, tuttavia sono riuscito a trasformarne una con Try catch(di @ user3359453) cambiando il tipo di eccezione lanciato ( KeyNotFoundExceptioninvece di RuntimeBinderException) in qualcosa che funziona davvero ...

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

inserisci qui la descrizione dell'immagine

Spero che questo ti faccia risparmiare tempo.


1
L'uso di eccezioni per cose come queste non è raccomandato. Avrei dovuto optare per qualcosa come il casting su JObject e l'utilizzo di .Property ()! = Null
Gaspa79

3

Unire e correggere le risposte da Serj-TM e user3359453 in modo che funzioni sia con ExpandoObject che con DynamicJsonObject. Questo funziona per me.

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

Usando la riflessione, questa è la funzione che uso:

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

poi..

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

2
GetProperties () non elenca il membro dinamico su un DynamicObject. C'è una funzione dedicata GetDynamicMemberNames () per questo.
Marco Guignard

L'uso Whereprima dell'espressione lambda , quindi, Anyè ridondante, poiché è possibile formulare anche l'espressione di filtro Any.
pholpar

1

Nel caso in cui qualcuno debba gestire un oggetto dinamico proveniente da Json, ho modificato la risposta di Seth Reno per gestire l'oggetto dinamico deserializzato da 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

Per estendere la risposta di @Kuroro, se devi testare se la proprietà è vuota, di seguito dovrebbe funzionare.

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;
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.