C #: reparto dynamic en tiempo de ejecución

Me gustaría implementar un método con la siguiente firma.

dynamic Cast(object obj, Type castTo); 

¿Alguien sabe cómo hacer eso? obj definitivamente implementa castTo pero necesita ser lanzado correctamente para que algunas de las cosas vinculantes en tiempo de ejecución de mi aplicación funcionen.

Edición: si algunas de las respuestas no tienen sentido, es porque inicialmente tecleé accidentalmente dynamic Cast(dynamic obj, Type castTo); – Quiero decir que la entrada debe ser un object o alguna otra clase base garantizada

Creo que estás confundiendo los problemas de casting y conversión aquí.

  • Casting: el acto de cambiar el tipo de una referencia que apunta a un objeto. Ya sea subiendo o bajando la jerarquía de objetos o hacia una interfaz implementada
  • Convertir: crear un nuevo objeto a partir del objeto fuente original de un tipo diferente y acceder a él a través de una referencia a ese tipo.

A menudo es difícil saber la diferencia entre el 2 en C # porque ambos usan el mismo operador de C #: el modelo.

En esta situación, es casi seguro que no está buscando una operación de lanzamiento. Convertir una dynamic en otra dynamic es esencialmente una conversión de identidad. No proporciona ningún valor porque solo está obteniendo una referencia dynamic al mismo objeto subyacente. La búsqueda resultante no sería diferente.

En su lugar, lo que parece querer en este escenario es una conversión. Eso es transformar el objeto subyacente a un tipo diferente y acceder al objeto resultante de forma dynamic . La mejor API para esto es Convert.ChangeType .

 public static dynamic Convert(dynamic source, Type dest) { return Convert.ChangeType(source, dest); } 

EDITAR

La pregunta actualizada tiene la siguiente línea:

obj definitivamente implementa castTo

Si este es el caso, entonces el método Cast no necesita existir. El object origen se puede asignar simplemente a una referencia dynamic .

 dynamic d = source; 

Parece que lo que está intentando lograr es ver una interfaz o un tipo en particular en la jerarquía de la source través de una referencia dynamic . Eso simplemente no es posible. La referencia dynamic resultante verá el objeto de implementación directamente. No mira a través de ningún tipo en particular en la jerarquía de la fuente. Entonces, la idea de convertir a un tipo diferente en la jerarquía y luego volver a dynamic es exactamente idéntica a la simple asignación de dynamic en primer lugar. Todavía apuntará al mismo objeto subyacente.

Esto debería funcionar:

 public static dynamic Cast(dynamic obj, Type castTo) { return Convert.ChangeType(obj, castTo); } 

Editar

He escrito el siguiente código de prueba:

 var x = "123"; var y = Cast(x, typeof(int)); var z = y + 7; var w = Cast(z, typeof(string)); // w == "130" 

Se parece al tipo de “encasillamiento” que se encuentra en lenguajes como PHP, JavaScript o Python (porque también convierte el valor al tipo deseado). No sé si eso es algo bueno, pero ciertamente funciona … 🙂

Lo mejor que tengo hasta ahora:

 dynamic DynamicCast(object entity, Type to) { var openCast = this.GetType().GetMethod("Cast", BindingFlags.Static | BindingFlags.NonPublic); var closeCast = openCast.MakeGenericMethod(to); return closeCast.Invoke(entity, new[] { entity }); } static T Cast(object entity) where T : class { return entity as T; } 

El framework de código abierto Dynamitey tiene un método estático que realiza un enlace tardío utilizando DLR, incluida la conversión de conversión entre otros .

 dynamic Cast(object obj, Type castTo){ return Dynamic.InvokeConvert(obj, castTo, explict:true); } 

La ventaja de esto sobre un Cast llamado mediante reflexión, es que esto también funcionará para cualquier IDynamicMetaObjectProvider que tenga operadores de conversión dinámica, es decir. TryConvert en DynamicObject .

Me doy cuenta de que esto ha sido respondido, pero utilicé un enfoque diferente y pensé que valdría la pena compartirlo. Además, siento que mi enfoque podría producir gastos indirectos no deseados. Sin embargo, no puedo observar ni calcular nada de lo que está sucediendo que es tan malo bajo las cargas que observamos. Estaba buscando cualquier comentario útil sobre este enfoque.

El problema con el trabajo con dinámica es que no puede adjuntar ninguna función al objeto dynamic directamente. Tienes que usar algo que pueda resolver las tareas que no quieres resolver cada vez.

Al planificar esta solución simple, observé cuáles son los intermediarios válidos al intentar volver a escribir objetos similares. Encontré que una matriz binaria, cadena (xml, json) o encoding en duro de una conversión ( IConvertable ) eran los enfoques habituales. No quiero entrar en conversiones binarias debido a un factor de mantenimiento del código y a la pereza.

Mi teoría era que Newtonsoft podía hacer esto usando un intermediario de cadena.

Como inconveniente, estoy bastante seguro de que al convertir la cadena en un objeto, que usaría la reflexión buscando en el ensamblaje actual un objeto con propiedades coincidentes, crear el tipo y luego crear una instancia de las propiedades, lo que requeriría una mayor reflexión. Si es verdad, todo esto puede considerarse una sobrecarga evitable.

DO#:

 //This lives in a helper class public static ConvertDynamic(dynamic data) { return Newtonsoft.Json.JsonConvert.DeserializeObject(Newtonsoft.Json.JsonConvert.SerializeObject(data)); } //Same helper, but in an extension class (public static class), //but could be in a base class also. public static ToModelList(this List list) { List retList = new List(); foreach(dynamic d in list) { retList.Add(ConvertDynamic(d)); } } 

Dicho esto, esto se ajusta a otra utilidad que he reunido que me permite convertir cualquier objeto en una dinámica. Sé que tuve que usar la reflexión para hacer eso correctamente:

 public static dynamic ToDynamic(this object value) { IDictionary expando = new ExpandoObject(); foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(value.GetType())) expando.Add(property.Name, property.GetValue(value)); return expando as ExpandoObject; } 

Tuve que ofrecer esa función. Un objeto arbitrario asignado a una variable de tipo dynamic no se puede convertir a un IDictionary, y romperá la función ConvertDynamic. Para que se use esta cadena de funciones, se debe proporcionar una dinámica de System.Dynamic.ExpandoObject, o IDictionary .

Pruebe un genérico:

 public static T CastTo(this dynamic obj, bool safeCast) where T:class { try { return (T)obj; } catch { if(safeCast) return null; else throw; } } 

Esto está en formato de método de extensión, por lo que su uso sería como si fuera un miembro de objetos dynamics:

 dynamic myDynamic = new Something(); var typedObject = myDynamic.CastTo(false); 

EDIT: Grr, no vi eso. Sí, podría cerrar el genérico de manera reflexiva y no sería difícil ocultarlo en un método de extensión no genérico:

 public static dynamic DynamicCastTo(this dynamic obj, Type castTo, bool safeCast) { MethodInfo castMethod = this.GetType().GetMethod("CastTo").MakeGenericMethod(castTo); return castMethod.Invoke(null, new object[] { obj, safeCast }); } 

Simplemente no estoy seguro de lo que obtendrías de esto. Básicamente, estás tomando una dinámica, forzando una conversión a un tipo reflejado, y luego volviéndolo a meter en una dinámica. Tal vez tienes razón, no debería preguntar. Pero, esto probablemente hará lo que quieras. Básicamente, cuando entras en el terreno dynamic, pierdes la necesidad de realizar la mayoría de las operaciones de lanzamiento, ya que puedes descubrir qué es un objeto y lo hace a través de métodos de reflexión o prueba y error, por lo que no hay muchas formas elegantes de hacerlo.

Alternativamente:

 public static T Cast(this dynamic obj) where T:class { return obj as T; }