Как проверить, существует ли свойство для динамического анонимного типа в C #?

122

У меня есть объект анонимного типа, который я получаю как динамический из метода, который я хотел бы проверить, существует ли свойство для этого объекта.

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

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

Как мне реализовать IsSettingExist?

Дэвид М.З.
источник
Если вы обнаружите, что сильно полагаетесь на динамические объекты, вероятно, стоит взглянуть на F # - Кстати, Хороший Аватар
Петр Кула

Ответы:

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

Вывод:

 True
 False
Serj-Tm
источник
3
Это не работает с динамическими объектами. Он всегда возвращает ноль.
evilom 06
@evilom @Shikasta_Kashti Вы пытаетесь использовать этот метод с MVC ViewBag? Если да, см. Stackoverflow.com/a/24192518/70345
Ян Кемп
@ Gaspa79. Это довольно распространенное соглашение о кодировании. Некоторым нравится префикс «Is» для всех логических свойств. Такая согласованность может избавить вас от необходимости угадывать первые несколько символов идентификатора (после чего Intellisense работает), но за счет создания немного неудобного английского языка в таких случаях.
solublefish
Я считаю, что неправильное время глагола Isпрефикса сбивает с толку больше, чем его можно было бы использовать в противном случае HasProperty. Я бы также сказал, что использование такого грамматически неверного префикса на самом деле не идиоматично в C♯.
Бен Коллинз
ExpandoObject - это не то же самое, что анонимный тип. Я ошибаюсь в этом?
Райанвебджексон,
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;
}
Сергей
источник
objType.GetProperty(name) != null;возвращает null для свойств, которые действительно существуют
Матас Вайткявичюс
3
objType.GetProperty(name) != nullвсегда будет возвращать a bool, чего (по определению) никогда не может быть null.
Alex McMillan
@AlexMcMillan Не уверен, в каком измерении вы живете, где Type.GetProperty(string)несуществующее свойство возвращает что-либо, кроме null.
Ян Кемп,
2
@IanKemp, AlexMcMillan фактически сказал objType.GetProperty (name)! = Null в ответ на комментарий MatasVaitkevicius.
Сергей
15

Если вы можете управлять созданием / передачей объекта настроек, я бы рекомендовал вместо этого использовать 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 ....
}
Майк Коркоран
источник
Я не могу его изменить, могу ли я преобразовать его в ExpendoObject?
David MZ
6

Это работает для анонимных типов или всего ExpandoObject, к Nancy.DynamicDictionaryчему можно привести 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
Отличное решение. Мне нужно было добавить еще один оператор IF при преобразовании строки JSON в JObject .... "if (obj is Newtonsoft.Json.Linq.JObject) return ((Newtonsoft.Json.Linq.JObject) obj) .ContainsKey (name); "
rr789
1
Также работал у меня. Замечательный ответ Сет Рино. Я также добавил «if (obj is Newtonsoft.Json.Linq.JObject) return ((Newtonsoft.Json.Linq.JObject) obj) .ContainsKey (name);» в функции выше, предложенной rr789. Поэтому, пожалуйста, также отредактируйте свой ответ, чтобы включить его.
Бриджеш Кумар Трипати,
1
Спасибо @BrijeshKumarTripathi! Это был именно мой сценарий.
Райанвебджексон,
4

Это работает для меня:

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

               return false;
           }

       }
user3359453
источник
14
Разрешение возникновения исключений с последующим их перехватом не является предпочтительным решением, потому что с выбросом и отловом связаны большие накладные расходы. Это только последнее средство. Исключения предназначены для ситуаций, которые не должны происходить в процессе выполнения, например, недоступность сети. Здесь есть гораздо лучшие решения.
Whatever Man
Сбой с RuntimeBinderExceptionи dynamicObj[property].Value когда значение на самом деле есть ... var value = dynamicObj[property]достаточно ... и когда она не существует KeyNotFoundException на Dictionaryброшено ... смотрите далее ...
Мейтаса Вайткявичюс
Использование исключений в бизнес-логике - недопустимое решение. 1 класс, 2 семестр.
Artem G
3

Ни одно из решений выше работал , dynamicчто приходит от Json, я тем не менее удалось превратить один с Try catch(на @ user3359453) путем изменения типа исключения брошенную ( KeyNotFoundExceptionвместо RuntimeBinderException) в то , что на самом деле работает ...

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

введите описание изображения здесь

Надеюсь, это сэкономит вам время.

Матас Вайткявичюс
источник
1
Не рекомендуется использовать исключения для подобных вещей. Надо было пойти на что-то вроде преобразования в JObject и использования .Property ()! =
Null
3

Объединение и исправление ответов от Serj-TM и user3359453, чтобы он работал как с ExpandoObject, так и с DynamicJsonObject. У меня это работает.

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

Используя отражение, я использую эту функцию:

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

затем..

if (doesPropertyExist(myDynamicObject, "myProperty")){
    // ...
}
Chtiwi Malek
источник
2
GetProperties () не перечисляет динамический член в DynamicObject. Для этого есть специальная функция GetDynamicMemberNames ().
Marco Guignard
WhereСначала используйте лямбда-выражение , а затем оно Anyявляется избыточным, так как вы также можете сформулировать свое выражение фильтрации Any.
pholpar
1

Если кому-то нужно обрабатывать динамический объект, исходящий из Json, я изменил ответ Сета Рино для обработки динамического объекта, десериализованного из 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
источник
0

Чтобы расширить ответ от @Kuroro, если вам нужно проверить, пусто ли свойство, ниже должно работать.

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;
}
Motz
источник