Lanzar una variable usando una variable Tipo

En C #, ¿puedo convertir una variable de tipo objeto en una variable de tipo T donde T se define en una variable Tipo?

Claro que puedes hacer aquí es un simple (supongo que es un elenco de tipo T) y si es conveniente (suponiendo que podemos convertir esto en un T) convertir:

 public T CastExamp1(object input) { return (T) input; } public T ConvertExamp1(object input) { return (T) Convert.ChangeType(input, typeof(T)); } 

Editar:

Algunas personas en los comentarios dicen que esta respuesta no responde la pregunta. Pero la línea (T) Convert.ChangeType(input, typeof(T)) proporciona la solución. El método Convert.ChangeType intenta convertir cualquier objeto al tipo proporcionado como segundo argumento.

He escrito la respuesta con generics, porque creo que es un signo muy probable de olor codificado cuando quieres transmitir a something a a something else sin manejar un tipo real. Con interfaces adecuadas que no deberían ser necesarias el 99.9% de las veces. Hay quizás algunos casos extremos cuando se trata de reflexionar que tiene sentido, pero recomendaría evitar esos casos.

Otras respuestas no mencionan el tipo “dynamic”. Entonces, para agregar una respuesta más, puede usar el tipo “dynamic” para almacenar su objeto resultante sin tener que convertir un objeto convertido con un tipo estático.

 dynamic changedObj = Convert.ChangeType(obj, typeVar); changedObj.Method(); 

Tenga en cuenta que con el uso de “dynamic” el comstackdor omite la verificación de tipo estático que podría introducir posibles errores de tiempo de ejecución si no tiene cuidado.

Este es mi método para convertir un objeto pero no a una variable de tipo genérico, sino a un System.Type forma dinámica:

Creo una expresión lambda en tiempo de ejecución usando System.Linq.Expressions , de tipo Func , que unboxes su entrada, realiza la conversión de tipo deseada y luego da el resultado encerrado. Se necesita una nueva, no solo para todos los tipos que se obtienen, sino también para los tipos que se obtienen (debido al paso de unboxing). La creación de estas expresiones consume mucho tiempo, debido a la reflexión, la comstackción y la creación de métodos dynamics que se realizan bajo el capó. Afortunadamente, una vez creadas, las expresiones se pueden invocar repetidamente y sin una sobrecarga, así que guardo en caché cada una.

 private static Func MakeCastDelegate(Type from, Type to) { var p = Expression.Parameter(typeof(object)); //do not inline return Expression.Lambda>( Expression.Convert(Expression.ConvertChecked(Expression.Convert(p, from), to), typeof(object)), p).Compile(); } private static readonly Dictionary, Func> CastCache = new Dictionary, Func>(); public static Func GetCastDelegate(Type from, Type to) { lock (CastCache) { var key = new Tuple(from, to); Func cast_delegate; if (!CastCache.TryGetValue(key, out cast_delegate)) { cast_delegate = MakeCastDelegate(from, to); CastCache.Add(key, cast_delegate); } return cast_delegate; } } public static object Cast(Type t, object o) { return GetCastDelegate(o.GetType(), t).Invoke(o); } 

Tenga en cuenta que esto no es mágico. El lanzamiento no ocurre en el código, como ocurre con la palabra clave dynamic , solo se convierten los datos subyacentes del objeto. En tiempo de comstackción todavía nos queda la tarea de descubrir qué tipo de objeto podría ser exactamente nuestro producto, lo que hace que esta solución no sea práctica. Escribí esto como un truco para invocar operadores de conversión definidos por tipos arbitrarios, pero tal vez alguien pueda encontrar un mejor caso de uso.

¿Como pudiste? Necesita una variable o campo de tipo T en el que pueda almacenar el objeto después del molde, pero ¿cómo puede tener esa variable o campo si conoce T solo en tiempo de ejecución? Entonces, no, no es posible.

 Type type = GetSomeType(); Object @object = GetSomeObject(); ??? xyz = @object.CastTo(type); // How would you declare the variable? xyz.??? // What methods, properties, or fields are valid here? 

Poniendo el boxeo y el desempaquetado a un lado por simplicidad, no hay una acción de tiempo de ejecución específica involucrada en la conversión a lo largo de la jerarquía de herencia. Es sobre todo una cosa de tiempo de comstackción. Esencialmente, un molde le dice al comstackdor que trate el valor de la variable como otro tipo.

¿Qué podrías hacer después del reparto? No conoce el tipo, por lo que no podrá llamar a ningún método. No habría nada especial que pudieras hacer. Específicamente, puede ser útil solo si conoce los tipos posibles en tiempo de comstackción, lo envía manualmente y maneja cada caso por separado con declaraciones if :

 if (type == typeof(int)) { int x = (int)obj; DoSomethingWithInt(x); } else if (type == typeof(string)) { string s = (string)obj; DoSomethingWithString(s); } // ... 
 public bool TryCast(ref T t, object o) { if ( o == null || !typeof(T).IsAssignableFrom(o.GetType()) ) return false; t = (T)o; return true; } 

incluso más limpio:

  public static bool TryCast(ref T t, object o) { if (!(o is T)) { return false; } t = (T)o; return true; } 

Cuando se trata de lanzar al tipo Enum:

 private static Enum GetEnum(Type type, int value) { if (type.IsEnum) if (Enum.IsDefined(type, value)) { return (Enum)Enum.ToObject(type, value); } return null; } 

Y lo llamarás así:

 var enumValue = GetEnum(typeof(YourEnum), foo); 

Esto fue esencial para mí en caso de obtener el valor del atributo Descripción de varios tipos enum por valor int:

 public enum YourEnum { [Description("Desc1")] Val1, [Description("Desc2")] Val2, Val3, } public static string GetDescriptionFromEnum(Enum value, bool inherit) { Type type = value.GetType(); System.Reflection.MemberInfo[] memInfo = type.GetMember(value.ToString()); if (memInfo.Length > 0) { object[] attrs = memInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), inherit); if (attrs.Length > 0) return ((DescriptionAttribute)attrs[0]).Description; } return value.ToString(); } 

y entonces:

 string description = GetDescriptionFromEnum(GetEnum(typeof(YourEnum), foo)); string description2 = GetDescriptionFromEnum(GetEnum(typeof(YourEnum2), foo2)); string description3 = GetDescriptionFromEnum(GetEnum(typeof(YourEnum3), foo3)); 

Alternativamente (mejor enfoque), tal conversión podría verse así:

  private static T GetEnum(int v) where T : struct, IConvertible { if (typeof(T).IsEnum) if (Enum.IsDefined(typeof(T), v)) { return (T)Enum.ToObject(typeof(T), v); } throw new ArgumentException(string.Format("{0} is not a valid value of {1}", v, typeof(T).Name)); }