2010-05-15 6 views
165

В JavaScript вы можете обнаружить, если свойство определяются с помощью ключевого слова неопределенного:Как определить, существует ли свойство в ExpandoObject?

if(typeof data.myProperty == "undefined") ... 

Как бы вы сделать это в C# с использованием динамического ключевым слова с ExpandoObject и не бросать исключение?

+5

@CodeInChaos: Обратите внимание, что отображаемый код не проверяет значение 'data.myProperty'; он проверяет, что возвращает 'typeof data.myProperty'. Правильно, что 'data.myProperty' может существовать и быть установлен в' undefined', но в этом случае 'typeof' вернет нечто, отличное от' 'undefined ''. Так что этот код действительно работает. –

ответ

154

Согласно MSDN декларация показывает, что она реализует IDictionary:

public sealed class ExpandoObject : IDynamicMetaObjectProvider, 
    IDictionary<string, Object>, ICollection<KeyValuePair<string, Object>>, 
    IEnumerable<KeyValuePair<string, Object>>, IEnumerable, INotifyPropertyChanged 

Вы можете использовать это, чтобы увидеть, если член определяется:

var expandoObject = ...; 
if(((IDictionary<String, object>)expandoObject).ContainsKey("SomeMember")) { 
    // expandoObject.SomeMember exists. 
} 
+3

Чтобы упростить эту проверку, я перегрузил TryGetValue и всегда возвращал true, устанавливая возвращаемое значение «undefined», если свойство не было определено. если (someObject.someParam! = «Неопределенные») ... И это работает :) – Softlion

+0

Также возможно :), но я думаю, что вы имели в виду «переопределены» вместо перегружен. – Dykam

+0

yep. Я снова изменил «undefined» на значение const const, которое я создал в другом месте. Это предотвращает проблемы с литьем: p – Softlion

1

Почему вы не хотите использовать Reflection для получить набор свойств типа? Нравится этим

dynamic v = new Foo(); 
Type t = v.GetType(); 
System.Reflection.PropertyInfo[] pInfo = t.GetProperties(); 
if (Array.Find<System.Reflection.PropertyInfo>(pInfo, p => { return p.Name == "PropName"; }). GetValue(v, null) != null)) 
{ 
    //PropName initialized 
} 
+0

Я не уверен, что который вернет динамически добавленные свойства, я предполагаю, что он возвращает методы динамического объекта. – Dykam

-4

Эй, ребята, прекратите использовать Reflection для всего, что это стоит много циклов процессора.

Вот решение:

public class DynamicDictionary : DynamicObject 
{ 
    Dictionary<string, object> dictionary = new Dictionary<string, object>(); 

    public int Count 
    { 
     get 
     { 
      return dictionary.Count; 
     } 
    } 

    public override bool TryGetMember(GetMemberBinder binder, out object result) 
    { 
     string name = binder.Name; 

     if (!dictionary.TryGetValue(binder.Name, out result)) 
      result = "undefined"; 

     return true; 
    } 

    public override bool TrySetMember(SetMemberBinder binder, object value) 
    { 
     dictionary[binder.Name] = value; 
     return true; 
    } 
} 
+4

Это показывает, как реализовать динамический объект, а не как его увидеть, что свойство выходит из динамического объекта. –

+0

Вы можете проверить, имеет ли динамический экземпляр свойство, выполнив нулевую проверку против рассматриваемого свойства. – ctorx

+6

Нет, вы не можете это исключить. – Softlion

11

Я ответил очень похожий вопрос в последнее время: How do I reflect over the members of dynamic object?

Вскоре ExpandoObject не единственный динамический объект, который вы могли бы получить. Отражение будет работать для статических типов (типов, которые не реализуют IDynamicMetaObjectProvider). Для типов, реализующих этот интерфейс, отражение в основном бесполезно. Для ExpandoObject вы можете просто проверить, определено ли свойство как ключ в базовом словаре. Для других реализаций это может быть сложной задачей, и иногда единственный способ - работать с исключениями. Для получения дополнительной информации перейдите по ссылке выше.

-4

Попробуйте один

public bool PropertyExist(object obj, string propertyName) 
{ 
return obj.GetType().GetProperty(propertyName) != null; 
} 
+3

Это проверит наличие свойства объекта, скрытого под динамическим именем, которое является деталью реализации. Вы проверяли свое решение в реальном коде перед публикацией? Это не должно работать вообще. – Softlion

+0

Я использовал этот фрагмент кода в реальном времени. Он работает хорошо. – Venkat

+6

Дает мне пустое время, даже если свойство существует. – atlantis

8

ОБНОВЛЕНО: Вы можете использовать делегаты и попытаться получить значение из свойства динамического объекта, если она существует. Если свойства нет, просто поймайте исключение и верните false.

Посмотрите, он отлично работает для меня:

class Program 
{ 
    static void Main(string[] args) 
    { 
     dynamic userDynamic = new JsonUser(); 

     Console.WriteLine(IsPropertyExist(() => userDynamic.first_name)); 
     Console.WriteLine(IsPropertyExist(() => userDynamic.address)); 
     Console.WriteLine(IsPropertyExist(() => userDynamic.last_name)); 
    } 

    class JsonUser 
    { 
     public string first_name { get; set; } 
     public string address 
     { 
      get 
      { 
       throw new InvalidOperationException("Cannot read property value"); 
      } 
     } 
    } 

    static bool IsPropertyExist(GetValueDelegate getValueMethod) 
    { 
     try 
     { 
      //we're not interesting in the return value. What we need to know is whether an exception occurred or not 
      getValueMethod(); 
      return true; 
     } 
     catch (RuntimeBinderException) 
     { 
      // RuntimeBinderException occurred during accessing the property 
      // and it means there is no such property   
      return false; 
     } 
     catch 
     { 
      //property exists, but an exception occurred during getting of a value 
      return true; 
     } 
    } 

    delegate string GetValueDelegate(); 
} 

Выход кода заключается в следующем:

True 
True 
False 
+0

@marklam Спасибо за комментарий. Но что вы имеете в виду? – alga

+0

Ловля всех исключений - это плохая практика, особенно для того, чтобы проглотить их все. http://www.dodgycoder.net/2011/11/yoda-conditions-pokemon-exception.html – marklam

+1

@marklam плохо поймать все исключения, когда вы не знаете, что вызывает исключение. В наших случаях это нормально, поскольку мы ожидаем, что возможно отсутствие поля. – alga

22

Важное различие должно быть сделано здесь.

Большинство ответов здесь относится к ExpandoObject, о котором говорится в вопросе. Но общее использование (и причина приземления на этот вопрос при поиске) заключается в использовании ASP.Net MVC ViewBag. Это специальная реализация/подкласс DynamicObject, которая не будет генерировать исключение при проверке любого произвольного имени свойства для null. Предположим, что вы могли бы объявить свойство как:

@{ 
    ViewBag.EnableThinger = true; 
} 

Тогда предположим, что вы хотели, чтобы проверить его значение, и будет ли он даже установить - существует ли оно.Далее действует, компилируется, не будет бросать никаких исключений, и дает правильный ответ:

if (ViewBag.EnableThinger != null && ViewBag.EnableThinger) 
{ 
    // Do some stuff when EnableThinger is true 
} 

Теперь избавиться от декларации EnableThinger. Тот же код компилируется и работает правильно. Не нужно размышлять.

В отличие от ViewBag, ExpandoObject будет метать, если вы проверите null для свойства, которое не существует. Чтобы получить более мягкую функциональность MVC ViewBag из ваших объектов dynamic, вам нужно будет использовать динамическую реализацию, которая не бросает.

Вы могли бы просто использовать точную реализацию в MVC ViewBag:

. . . 
public override bool TryGetMember(GetMemberBinder binder, out object result) 
{ 
    result = ViewData[binder.Name]; 
    // since ViewDataDictionary always returns a result even if the key does not exist, always return true 
    return true; 
} 
. . . 

https://github.com/ASP-NET-MVC/aspnetwebstack/blob/master/src/System.Web.Mvc/DynamicViewDataDictionary.cs

Вы можете видеть, что это связано в MVC Просмотров здесь, в MVC ViewPage:

http://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Mvc/ViewPage.cs

Ключом к грациозному поведению DynamicViewDataDictionary является реализация словаря на ViewDataDicti onary, здесь:

public object this[string key] 
{ 
    get 
    { 
     object value; 
     _innerDictionary.TryGetValue(key, out value); 
     return value; 
    } 
    set { _innerDictionary[key] = value; } 
} 

https://github.com/ASP-NET-MVC/aspnetwebstack/blob/master/src/System.Web.Mvc/ViewDataDictionary.cs

Другими словами, он всегда возвращает значение для всех ключей, независимо от того, что в нем - это просто возвращает нуль, если ничего не есть. Но, ViewDataDictionary несет ответственность за привязку к модели MVC, поэтому лучше выделять только изящные части словаря для использования вне MVC Views.

Это слишком долго, чтобы действительно поместить все кишки здесь - большинство из них просто реализует IDictionary - но вот динамический объект, который не бросает нулевых проверок на свойства, которые не были заявлены на Github:

https://github.com/b9chris/GracefulDynamicDictionary

Если вы просто хотите добавить его в свой проект через NuGet, его имя будет GracefulDynamicDictionary.

+0

Почему вы проголосовали за DynamicDictionary, поскольку он не использует отражение? – Softlion

+0

? Я этого не сделал. http://i.imgur.com/hULJMg0.png –

+0

, то вы можете проголосовать за него, поскольку это то же самое решение :) – Softlion

-2
(authorDynamic as ExpandoObject).Any(pair => pair.Key == "YourProp"); 
3

Я хотел создать метод расширения , так что я мог бы сделать что-то вроде:

dynamic myDynamicObject; 
myDynamicObject.propertyName = "value"; 

if (myDynamicObject.HasProperty("propertyName")) 
{ 
    //... 
} 

... но вы не можете создавать расширения на ExpandoObject в соответствии с документацией на C# 5 (более info here).

Так что я в конечном итоге создать класс помощника:

метод
public static class ExpandoObjectHelper 
{ 
    public static bool HasProperty(ExpandoObject obj, string propertyName) 
    { 
     return ((IDictionary<String, object>)obj).ContainsKey(propertyName); 
    } 
} 
+1

за полезный комментарий и ссылку на расширения для ExpandoObject. – Roberto

1

Это расширение проверяет на наличие свойства, а затем возвращает значение или нуль. Это полезно, если вы не хотите, чтобы ваши приложения выбрасывали ненужные исключения, по крайней мере, те, которые вы можете вам помочь.

public static object Value(this ExpandoObject expando, string name) 
    { 
     var expandoDic = (IDictionary<string, object>)expando; 
     return expandoDic.ContainsKey(name) ? expandoDic[name] : null; 
    } 

Если могут быть использованы в качестве таковых:

// lookup is type 'ExpandoObject' 
    object value = lookup.Value("MyProperty"); 

или если ваша локальная переменная «динамический» вам придется бросить его ExpandoObject первым.

// lookup is type 'dynamic' 
    object value = ((ExpandoObject)lookup).Value("PropertyBeingTested"); 
Смежные вопросы