Mi situación es muy simple. En algún lugar de mi código tengo esto:
dynamic myVariable = GetDataThatLooksVerySimilarButNotTheSame();
//How to do this?
if (myVariable.MyProperty.Exists)
//Do stuff
Entonces, básicamente mi pregunta es cómo verificar (sin lanzar una excepción) que una determinada propiedad esté disponible en mi variable dinámica. Podría hacerlo, GetType()
pero prefiero evitar eso, ya que realmente no necesito saber el tipo de objeto. Todo lo que realmente quiero saber es si una propiedad (o método, si eso facilita la vida) está disponible. Cualquier puntero?
c#
dynamic
dynamic-keyword
crisis redonda
fuente
fuente
Respuestas:
Creo que no hay forma de averiguar si una
dynamic
variable tiene un miembro determinado sin intentar acceder a ella, a menos que vuelva a implementar la forma en que se maneja el enlace dinámico en el compilador de C #. Lo que probablemente incluiría muchas conjeturas, porque está definido por la implementación, de acuerdo con la especificación C #.Por lo tanto, debería intentar acceder al miembro y detectar una excepción, si falla:
fuente
IDictionary
y trabajar con eso, eso solo funcionaExpandoObject
, no funcionará en ningún otrodynamic
objeto.RuntimeBinderException
está en elMicrosoft.CSharp.RuntimeBinder
espacio de nombres.Yo pensé en hacer una comparación de la respuesta de Martijn y la respuesta de svick ...
El siguiente programa devuelve los siguientes resultados:
Como resultado, sugeriría usar la reflexión.Vea abajo.En respuesta al comentario de bland:
Las relaciones son
reflection:exception
ticks para 100000 iteraciones:... bastante justo: si espera que falle con una probabilidad con menos de ~ 1/47, entonces elija una excepción.
Lo anterior supone que estás corriendo
GetProperties()
cada vez. Es posible que pueda acelerar el proceso almacenando en caché el resultado deGetProperties()
cada tipo en un diccionario o similar. Esto puede ayudar si está comprobando el mismo conjunto de tipos una y otra vez.fuente
IIDynamicMetaObjectProvider
. Entiendo la motivación detrás de su respuesta, y lo aprecio. Es justo responder eso.Tal vez usar la reflexión?
fuente
Where
:.Any(p => p.Name.Equals("PropertyName"))
((Type)myVar.GetType()).GetProperties().Any(x => x.Name.Equals("PropertyName"))
. Se requiere la conversión para escribir para que el compilador esté contento con la lambda.Por si acaso ayuda a alguien:
Si el método
GetDataThatLooksVerySimilarButNotTheSame()
devuelve unExpandoObject
también puede lanzar aIDictionary
antes de verificar.fuente
Las dos soluciones comunes a esto incluyen hacer la llamada y capturarla
RuntimeBinderException
, usar la reflexión para verificar la llamada o serializar a un formato de texto y analizar desde allí. El problema con las excepciones es que son muy lentas, porque cuando se construye una, la pila de llamadas actual se serializa. Serializar a JSON o algo análogo incurre en una penalización similar. Esto nos deja con reflexión, pero solo funciona si el objeto subyacente es en realidad un POCO con miembros reales en él. Si se trata de un contenedor dinámico alrededor de un diccionario, un objeto COM o un servicio web externo, la reflexión no ayudará.Otra solución es usar el
DynamicMetaObject
para obtener los nombres de los miembros como los ve el DLR. En el ejemplo a continuación, uso una clase estática (Dynamic
) para probar elAge
campo y mostrarlo.fuente
Dynamitey
paquete nuget ya hace esto. ( nuget.org/packages/Dynamitey )La respuesta de Denis me hizo pensar en otra solución usando JsonObjects,
un verificador de propiedad de encabezado:
o tal vez mejor:
por ejemplo:
fuente
Bueno, enfrenté un problema similar pero en pruebas unitarias.
Usando SharpTestsEx puede verificar si existe una propiedad. Utilizo esta prueba de mis controladores, porque dado que el objeto JSON es dinámico, alguien puede cambiar el nombre y olvidar cambiarlo en JavaScript o algo así, por lo que probar todas las propiedades al escribir el controlador debería aumentar mi seguridad.
Ejemplo:
Ahora, usando SharTestsEx:
Con esto, pruebo todas las propiedades existentes con "should (). NotThrow ()".
Probablemente esté fuera de tema, pero puede ser útil para alguien.
fuente
((string)(testedObject.MyName)).Should().Be("I am a testing object");
Siguiendo con la respuesta de @karask, podría ajustar la función como ayudante de esta manera:
fuente
Para mí esto funciona:
fuente
null
no significa que la propiedad no existaSi controla el tipo que se usa como dinámico, ¿no podría devolver una tupla en lugar de un valor para cada acceso de propiedad? Algo como...
Posiblemente una implementación ingenua, pero si construye uno de estos internamente cada vez y devuelve eso en lugar del valor real, puede verificar
Exists
cada acceso a la propiedad y luego presionarValue
si lo hace con valordefault(T)
(e irrelevante) si no lo hace.Dicho esto, podría estar perdiendo algunos conocimientos sobre cómo funciona la dinámica y esto podría no ser una sugerencia viable.
fuente
En mi caso, necesitaba verificar la existencia de un método con un nombre específico, así que usé una interfaz para eso
Además, las interfaces pueden contener más que solo métodos:
De: Interfaces (Guía de programación de C #)
Elegante y sin necesidad de atrapar excepciones o jugar con la reflexión ...
fuente
Sé que esta es una publicación muy antigua, pero aquí hay una solución simple para trabajar con
dynamic
escribirc#
.fuente
Como
ExpandoObject
hereda elIDictionary<string, object>
puede usar la siguiente comprobaciónPuede hacer un método de utilidad para realizar esta verificación, que hará que el código sea mucho más limpio y reutilizable
fuente
Aquí está la otra manera:
fuente
dynamic
.dynamic
La palabra clave es un tema mucho más amplio. Ir cheque si se puede probarCount
endynamic foo = new List<int>{ 1,2,3,4 }
el estilo