Comment vérifier si une propriété existe sur un type anonyme dynamique en c #?

122

J'ai un objet de type anonyme que je reçois en tant que dynamique d'une méthode que je voudrais vérifier qu'une propriété existe sur cet objet.

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

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

Comment implémenter IsSettingExist?

David MZ
la source
2
Double
Sebastian
Si vous vous sentez fortement dépendant des objets dynamiques, il vaut probablement la peine de regarder F # - Nice Avatar au fait
Piotr Kula

Réponses:

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

Production:

 True
 False
Serj-Tm
la source
3
Cela ne fonctionne pas sur les objets dynamiques. Il renvoie toujours null.
evilom
@evilom @Shikasta_Kashti Essayez-vous d'utiliser cette méthode avec un MVC ViewBag? Si tel est le cas, voir stackoverflow.com/a/24192518/70345
Ian Kemp
@ Gaspa79. C'est une convention de codage qui n'est pas rare. Certaines personnes aiment un préfixe "Est" sur toutes les propriétés booléennes. Une telle cohérence peut vous éviter d'avoir à deviner les premiers caractères d'un identifiant (après quoi, Intellisense fonctionne), mais au détriment de faire un anglais un peu gênant dans des cas comme celui-ci.
solublefish
Je trouve que le temps du verbe invalide du Ispréfixe est plus déroutant qu'il ne le serait autrement HasProperty. Je dirais aussi que l'utilisation d'un préfixe grammaticalement incorrect comme celui-ci n'est en fait pas idiomatique en C♯.
Ben Collins
ExpandoObject n'est pas la même chose que le type anonyme. Est-ce que je me trompe?
ryanwebjackson
38
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
la source
objType.GetProperty(name) != null;renvoie null sur les propriétés qui existent
Matas Vaitkevicius
3
objType.GetProperty(name) != nullretournera toujours a bool, ce qui (par définition) ne peut jamais être null.
Alex McMillan
@AlexMcMillan Je ne sais pas dans quelle dimension vous vivez où Type.GetProperty(string)pour une propriété inexistante renvoie autre chose que null.
Ian Kemp
2
@IanKemp, AlexMcMillan a dit objType.GetProperty (nom)! = Null en réponse au commentaire de MatasVaitkevicius en fait.
Sergey
15

si vous pouvez contrôler la création / la transmission de l'objet de paramètres, je vous recommande d'utiliser un ExpandoObject à la place.

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
la source
Je ne peux pas le changer, puis-je lancer sur ExpendoObject?
David MZ
6

Cela fonctionne pour des types anonymes, ExpandoObject, Nancy.DynamicDictionaryou toute autre chose qui peut être exprimées pour 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
la source
2
Excellente solution. J'avais besoin d'ajouter une instruction IF supplémentaire lors de la conversion de la chaîne JSON en JObject .... "if (obj is Newtonsoft.Json.Linq.JObject) return ((Newtonsoft.Json.Linq.JObject) obj) .ContainsKey (name); "
rr789 le
1
A également travaillé pour moi. Merveilleuse réponse Seth Reno. J'ai également ajouté "if (obj is Newtonsoft.Json.Linq.JObject) return ((Newtonsoft.Json.Linq.JObject) obj) .ContainsKey (name);" dans la fonction ci-dessus comme suggéré par rr789. Veuillez donc également modifier votre réponse pour l'inclure.
Brijesh Kumar Tripathi
1
Merci @BrijeshKumarTripathi! C'était exactement mon scénario.
ryanwebjackson
4

Cela fonctionne pour moi-:

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

               return false;
           }

       }
user3359453
la source
14
Autoriser les exceptions à se produire, puis les attraper n'est pas une solution préférée car il y a beaucoup de frais généraux associés au lancement et à la capture. C'est un dernier recours seulement. Les exceptions sont conçues pour des situations qui ne devraient pas se produire au cours de l'exécution, comme un réseau indisponible. Il existe de bien meilleures solutions ici.
Whatever Man
Échoue avec RuntimeBinderExceptionet dynamicObj[property].Value quand la valeur est réellement là ... var value = dynamicObj[property]suffit ... et quand elle n'existe pas, KeyNotFoundException on Dictionaryjette ... voir ci-dessous ...
Matas Vaitkevicius
L'utilisation d'exceptions dans la logique métier n'est pas une solution acceptable. 1 année, 2e quadrimestre.
Artem G
3

Aucune des solutions ci-dessus n'a fonctionné pour dynamiccela Json, j'ai cependant réussi à en transformer une avec Try catch(par @ user3359453) en changeant le type d'exception lancé ( KeyNotFoundExceptionau lieu de RuntimeBinderException) en quelque chose qui fonctionne réellement ...

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

entrez la description de l'image ici

J'espère que cela vous fera gagner du temps.

Matas Vaitkevicius
la source
1
L'utilisation d'exceptions pour des choses comme celles-ci n'est pas recommandée. J'aurais dû opter pour quelque chose comme la diffusion sur JObject et l'utilisation de .Property ()! = Null
Gaspa79
3

Fusion et correction des réponses de Serj-TM et user3359453 afin qu'il fonctionne à la fois avec ExpandoObject et DynamicJsonObject. Cela fonctionne pour moi.

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
la source
2

En utilisant la réflexion, c'est la fonction que j'utilise:

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

puis..

if (doesPropertyExist(myDynamicObject, "myProperty")){
    // ...
}
Chtiwi Malek
la source
2
GetProperties () ne répertorie pas les membres dynamiques sur un objet DynamicObject. Il existe une fonction dédiée GetDynamicMemberNames () pour cela.
Marco Guignard le
Utiliser d'abord l'expression lambda Where, puis Anyest redondant, car vous pouvez également formuler votre expression de filtrage Any.
pholpar
1

Au cas où quelqu'un aurait besoin de gérer un objet dynamique provenant de Json, j'ai modifié la réponse de Seth Reno pour gérer l'objet dynamique désérialisé de 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
la source
0

Pour étendre la réponse de @Kuroro, si vous devez tester si la propriété est vide, ci-dessous devrait fonctionner.

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
la source