En javascript, vous pouvez détecter si une propriété est définie en utilisant le mot-clé undefined:
if( typeof data.myProperty == "undefined" ) ...
Comment feriez-vous cela en C # en utilisant le mot-clé dynamic avec ExpandoObject
et sans lever d'exception?
c#
dynamic
expandoobject
Softlion
la source
la source
data.myProperty
; il vérifie ce quitypeof data.myProperty
revient. Il est correct que celadata.myProperty
puisse exister et être défini surundefined
, mais dans ce cas,typeof
il renverra autre chose que"undefined"
. Donc, ce code fonctionne.Réponses:
Selon MSDN, la déclaration montre qu'elle implémente IDictionary:
public sealed class ExpandoObject : IDynamicMetaObjectProvider, IDictionary<string, Object>, ICollection<KeyValuePair<string, Object>>, IEnumerable<KeyValuePair<string, Object>>, IEnumerable, INotifyPropertyChanged
Vous pouvez l'utiliser pour voir si un membre est défini:
var expandoObject = ...; if(((IDictionary<String, object>)expandoObject).ContainsKey("SomeMember")) { // expandoObject.SomeMember exists. }
la source
Une distinction importante doit être faite ici.
La plupart des réponses ici sont spécifiques à ExpandoObject qui est mentionné dans la question. Mais une utilisation courante (et une raison de se poser sur cette question lors de la recherche) est l'utilisation du ViewBag ASP.Net MVC. C'est une implémentation / sous-classe personnalisée de DynamicObject, qui ne lèvera pas d'exception lorsque vous vérifiez un nom de propriété arbitraire pour null. Supposons que vous puissiez déclarer une propriété comme:
@{ ViewBag.EnableThinger = true; }
Supposons alors que vous vouliez vérifier sa valeur, et si elle est même définie - si elle existe. Ce qui suit est valide, compilera, ne lèvera aucune exception et vous donnera la bonne réponse:
if (ViewBag.EnableThinger != null && ViewBag.EnableThinger) { // Do some stuff when EnableThinger is true }
Débarrassez-vous maintenant de la déclaration de EnableThinger. Le même code se compile et s'exécute correctement. Pas besoin de réflexion.
Contrairement à ViewBag, ExpandoObject lancera si vous vérifiez la valeur null sur une propriété qui n'existe pas. Afin d'obtenir les fonctionnalités plus douces de MVC ViewBag de vos
dynamic
objets, vous devrez utiliser une implémentation de dynamique qui ne lance pas.Vous pouvez simplement utiliser l'implémentation exacte dans 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
Vous pouvez le voir lié aux vues MVC ici, dans MVC ViewPage:
http://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Mvc/ViewPage.cs
La clé du comportement gracieux de DynamicViewDataDictionary est l'implémentation du dictionnaire sur ViewDataDictionary, ici:
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
In other words, it always returns a value for all keys, regardless of what's in it - it simply returns null when nothing's there. But, ViewDataDictionary has the burden of being tied to MVC's Model, so it's better to strip out just the graceful dictionary parts for use outside MVC Views.
It's too long to really post all the guts here - most of it just implementing IDictionary - but here's a dynamic object (class
DDict
) that doesn't throw for null checks on properties that haven't been declared, on Github:https://github.com/b9chris/GracefulDynamicDictionary
If you just want to add it to your project via NuGet, its name is GracefulDynamicDictionary.
la source
I answered a very similar question recently: How do I reflect over the members of dynamic object?
Shortly, ExpandoObject is not the only dynamic object you might get. Reflection would work for static types (types that do not implement IDynamicMetaObjectProvider). For types that do implement this interface, reflection is basically useless. For ExpandoObject, you can simply check whether the property is defined as a key in the underlying dictionary. For other implementations, it might be challenging and sometimes the only way is to work with exceptions. For details, follow the link above.
la source
UPDATED: You can use delegates and try to get a value from the dynamic object property if it exists. If there is no property, simply catch the exception and return false.
Take a look, it works fine for me:
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(); }
The output of the code is the following:
la source
IsPropertyExist
. In this example, you know one can throw anInvalidOperationException
. In practice, you have no idea what exception may be thrown. +1 to counteract the cargo cult.I wanted to create an extension method so I could do something like:
dynamic myDynamicObject; myDynamicObject.propertyName = "value"; if (myDynamicObject.HasProperty("propertyName")) { //... }
... but you can't create extensions on
ExpandoObject
according to the C# 5 documentation (more info here).So I ended up creating a class helper:
public static class ExpandoObjectHelper { public static bool HasProperty(ExpandoObject obj, string propertyName) { return ((IDictionary<String, object>)obj).ContainsKey(propertyName); } }
To use it:
// If the 'MyProperty' property exists... if (ExpandoObjectHelper.HasProperty(obj, "MyProperty")) { ... }
la source
Why you do not want to use Reflection to get set of type properyes? Like this
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 }
la source
This extension method checks for the existence of a property and then returns the value or null. This is useful if you do not want your applications to throw unnecessary exceptions, at least ones you can help.
public static object Value(this ExpandoObject expando, string name) { var expandoDic = (IDictionary<string, object>)expando; return expandoDic.ContainsKey(name) ? expandoDic[name] : null; }
If can be used as such :
// lookup is type 'ExpandoObject' object value = lookup.Value("MyProperty");
or if your local variable is 'dynamic' you will have to cast it to ExpandoObject first.
// lookup is type 'dynamic' object value = ((ExpandoObject)lookup).Value("PropertyBeingTested");
la source
Depending on your use case, if null can be considered as being the same as undefined, you can turn your ExpandoObject into a DynamicJsonObject.
dynamic x = new System.Web.Helpers.DynamicJsonObject(new ExpandoObject()); x.a = 1; x.b = 2.50; Console.WriteLine("a is " + (x.a ?? "undefined")); Console.WriteLine("b is " + (x.b ?? "undefined")); Console.WriteLine("c is " + (x.c ?? "undefined"));
Output:
a is 1 b is 2.5 c is undefined
la source
(authorDynamic as ExpandoObject).Any(pair => pair.Key == "YourProp");
la source
Hey guys stop using Reflection for everything it costs a lots of CPU cycles.
Here is the solution:
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; } }
la source
Try this one
public bool PropertyExist(object obj, string propertyName) { return obj.GetType().GetProperty(propertyName) != null; }
la source
dynamic
objects either (always returnsnull
).