Як перевірити, чи існує властивість динамічного анонімного типу в c #?


122

У мене є об'єкт анонімного типу, який я отримую як динамічний метод, який я хотів би перевірити, чи існує властивість цього об'єкта.

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

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

Як я можу реалізувати IsSettingExist?



Якщо ви знаєте, що сильно покладаєтесь на динамічні об'єкти, то, мабуть, варто подивитися на F # - Nice Avatar, до речі
Piotr Kula

Відповіді:


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

Вихід:

 True
 False

3
Це не працює на динамічних об'єктах. Він завжди повертається до нуля.
evili

@evili @Shikasta_Kashti Ви намагаєтесь використовувати цей метод із MVC ViewBag? Якщо так, дивіться stackoverflow.com/a/24192518/70345
Ян Кемп

@ Gaspa79. Це нечаста умова кодування. Деякі люди, як префікс "Є", мають усі булі властивості. Така послідовність може заважати вам не вгадувати перші кілька символів ідентифікатора (після чого Intellisense працює), але за рахунок створення трохи незграбної англійської мови у подібних випадках.
розчинна риба

Я вважаю, що недійсне дієслово Isпрефікса є більш заплутаним, ніж було б інакше використовувати HasProperty. Я б також сказав, що використання граматично неправильного префікса, як це, насправді в C♯ неідіоматичне.
Бен Коллінз

ExpandoObject - це не те саме, що анонімний тип. Я з цим помиляюся?
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;повертає нуль за властивостями, які існують
Matas Vaitkevicius

3
objType.GetProperty(name) != nullзавжди поверне a bool, що (за визначенням) ніколи не може бути null.
Алекс Макміллан

@AlexMcMillan Не впевнений, у якому вимірі ви живете, коли Type.GetProperty(string)для неіснуючого властивості повертається що-небудь, крім null.
Ян Кемп

2
@IanKemp, AlexMcMillan сказав objType.GetProperty (ім'я)! = 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?
Девід МЗ

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 - Newtonsoft.Json.Linq.JObject) return ((Newtonsoft.Json.Linq.JObject) obj) .ContainsKey (name); "
rr789

1
Також працював на мене. Чудова відповідь Сет Рено. Я також додав "if (obj - Newtonsoft.Json.Linq.JObject) return ((Newtonsoft.Json.Linq.JObject) obj) .ContainsKey (name);" у наведеній вище функції, як запропоновано rr789 Тому, будь ласка, відредагуйте свою відповідь, щоб включити її.
Brijesh Kumar Tripathi

1
Дякую @BrijeshKumarTripathi! Це був саме мій сценарій.
ryanwebjackson

4

Це працює для мене:

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

               return false;
           }

       }

14
Допускати виникнення винятків, а потім їх ловити, не є бажаним рішенням, оскільки існує велика кількість накладних витрат, пов’язаних із метанням та ловом. Це лише в крайньому випадку. Винятки призначені для ситуацій, які не повинні відбуватися в ході виконання, наприклад, недоступність мережі. Тут набагато кращі рішення.
Яка б людина не була

Збій з RuntimeBinderExceptionі dynamicObj[property].Value коли значення насправді є ... var value = dynamicObj[property]досить ... і коли вона не існує KeyNotFoundException на Dictionaryкинуто ... дивіться далі ...
Мейтаса Вайткявічюс

Неприйнятне рішення використовувати винятки в бізнес-логіці. 1 клас, 2 клас.
Артем Г

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
Gaspa79

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")){
    // ...
}

2
GetProperties () не відображає динамічного учасника в DynamicObject. Для цього є виділена функція GetDynamicMemberNames ().
Марко Гіньярд

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;
    }

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;
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.