Respuestas:
Según MSDN, la declaración muestra que está implementando IDictionary:
public sealed class ExpandoObject : IDynamicMetaObjectProvider,
IDictionary<string, Object>, ICollection<KeyValuePair<string, Object>>,
IEnumerable<KeyValuePair<string, Object>>, IEnumerable, INotifyPropertyChanged
Puede usar esto para ver si un miembro está definido:
var expandoObject = ...;
if(((IDictionary<String, object>)expandoObject).ContainsKey("SomeMember")) {
// expandoObject.SomeMember exists.
}
Una distinción importante debe hacerse aquí.
La mayoría de las respuestas aquí son específicas del ExpandoObject que se menciona en la pregunta. Pero un uso común (y una razón para aterrizar en esta pregunta cuando se busca) es cuando se usa ASP.Net MVC ViewBag. Esa es una implementación / subclase personalizada de DynamicObject, que no arrojará una excepción cuando verifique cualquier nombre de propiedad arbitrario para nulo. Suponga que puede declarar una propiedad como:
@{
ViewBag.EnableThinger = true;
}
Luego, suponga que desea verificar su valor y si está configurado, si existe. Lo siguiente es válido, compilará, no arrojará ninguna excepción y le dará la respuesta correcta:
if (ViewBag.EnableThinger != null && ViewBag.EnableThinger)
{
// Do some stuff when EnableThinger is true
}
Ahora deshazte de la declaración de EnableThinger. El mismo código se compila y se ejecuta correctamente. No hay necesidad de reflexión.
A diferencia de ViewBag, ExpandoObject se lanzará si verifica nulo en una propiedad que no existe. Para sacar la funcionalidad más suave de MVC ViewBag de sus dynamic
objetos, necesitará usar una implementación de dinámica que no arroje.
Simplemente puede usar la implementación exacta en 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;
}
. . .
Puede ver que está vinculado a MVC Views aquí, en MVC ViewPage:
http://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Mvc/ViewPage.cs
La clave del comportamiento elegante de DynamicViewDataDictionary es la implementación del Diccionario en ViewDataDictionary, aquí:
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
En otras palabras, siempre devuelve un valor para todas las claves, independientemente de lo que contenga, simplemente devuelve nulo cuando no hay nada allí. Pero, ViewDataDictionary tiene la carga de estar atado al modelo de MVC, por lo que es mejor eliminar solo las elegantes partes del diccionario para usar fuera de las vistas de MVC.
Es demasiado tiempo para publicar realmente todas las agallas aquí, la mayoría solo implementando IDictionary, pero aquí hay un objeto dinámico (clase DDict
) que no arroja controles nulos en propiedades que no se han declarado, en Github:
https://github.com/b9chris/GracefulDynamicDictionary
Si solo desea agregarlo a su proyecto a través de NuGet, su nombre es GracefulDynamicDictionary .
Respondí una pregunta muy similar recientemente: ¿Cómo reflexiono sobre los miembros del objeto dinámico?
En breve, ExpandoObject no es el único objeto dinámico que puede obtener. Reflection funcionaría para tipos estáticos (tipos que no implementan IDynamicMetaObjectProvider). Para los tipos que implementan esta interfaz, la reflexión es básicamente inútil. Para ExpandoObject, simplemente puede verificar si la propiedad está definida como una clave en el diccionario subyacente. Para otras implementaciones, puede ser un desafío y, a veces, la única forma es trabajar con excepciones. Para más detalles, siga el enlace de arriba.
ACTUALIZADO: puede usar delegados e intentar obtener un valor de la propiedad del objeto dinámico si existe. Si no hay propiedad, simplemente captura la excepción y devuelve falso.
Echa un vistazo, me funciona bien:
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();
}
La salida del código es la siguiente:
True
True
False
IsPropertyExist
. En este ejemplo, sabes que uno puede lanzar un InvalidOperationException
. En la práctica, no tienes idea de qué excepción se puede lanzar. +1 para contrarrestar el culto a la carga.
Quería crear un método de extensión para poder hacer algo como:
dynamic myDynamicObject;
myDynamicObject.propertyName = "value";
if (myDynamicObject.HasProperty("propertyName"))
{
//...
}
... pero no puede crear extensiones de ExpandoObject
acuerdo con la documentación de C # 5 (más información aquí ).
Así que terminé creando un ayudante de clase:
public static class ExpandoObjectHelper
{
public static bool HasProperty(ExpandoObject obj, string propertyName)
{
return ((IDictionary<String, object>)obj).ContainsKey(propertyName);
}
}
Para usarlo:
// If the 'MyProperty' property exists...
if (ExpandoObjectHelper.HasProperty(obj, "MyProperty"))
{
...
}
¿Por qué no desea utilizar Reflection para obtener un conjunto de tipos de propiedad sí? Me gusta esto
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
}
Este método de extensión verifica la existencia de una propiedad y luego devuelve el valor o nulo. Esto es útil si no desea que sus aplicaciones arrojen excepciones innecesarias, al menos las que puede ayudar.
public static object Value(this ExpandoObject expando, string name)
{
var expandoDic = (IDictionary<string, object>)expando;
return expandoDic.ContainsKey(name) ? expandoDic[name] : null;
}
Si se puede usar como tal:
// lookup is type 'ExpandoObject'
object value = lookup.Value("MyProperty");
o si su variable local es 'dinámica', primero deberá convertirla a ExpandoObject.
// lookup is type 'dynamic'
object value = ((ExpandoObject)lookup).Value("PropertyBeingTested");
Dependiendo de su caso de uso, si puede considerarse que nulo es igual a indefinido, puede convertir su ExpandoObject en un 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"));
Salida:
a is 1
b is 2.5
c is undefined
(authorDynamic as ExpandoObject).Any(pair => pair.Key == "YourProp");
Hola chicos, dejen de usar Reflection para todo lo que cuesta muchos ciclos de CPU.
Aquí está la solución:
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;
}
}
Prueba este
public bool PropertyExist(object obj, string propertyName)
{
return obj.GetType().GetProperty(propertyName) != null;
}
dynamic
objetos (siempre regresa null
).
data.myProperty
; Comprueba lo quetypeof data.myProperty
vuelve. Es correcto quedata.myProperty
pueda existir y establecerse enundefined
, pero en ese caso,typeof
devolverá algo distinto de"undefined"
. Entonces este código funciona.