tipo - ref string parameter c#
Convertir una variable usando una variable Tipo (9)
En C #, ¿puedo convertir una variable de tipo objeto a una variable de tipo T donde T se define en una variable de tipo?
¿Como pudiste? Necesita una variable o un campo de tipo T donde pueda almacenar el objeto después del lanzamiento, pero ¿cómo puede tener una variable o un campo de este tipo 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?
Aquí es mi método para convertir un objeto, pero no a una variable de tipo genérico, en lugar de un System.Type
dinámicamente:
Creo una expresión lambda en tiempo de ejecución utilizando System.Linq.Expressions
, de tipo Func<object, object>
, que desempaqueta su entrada, realiza la conversión de tipo deseada y luego da el resultado en caja. Se necesita uno nuevo, no solo para todos los tipos que se lanzan, sino también para los tipos que se emiten (debido al paso de desempaquetado). La creación de estas expresiones requiere mucho tiempo, debido a la reflexión, la compilación y el método dinámico que se realiza bajo el capó. Por suerte, una vez creada, las expresiones pueden ser invocados en varias ocasiones y sin altos gastos indirectos, por lo que guardan en caché cada uno.
private static Func<object, object> MakeCastDelegate(Type from, Type to)
{
var p = Expression.Parameter(typeof(object)); //do not inline
return Expression.Lambda<Func<object, object>>(
Expression.Convert(Expression.ConvertChecked(Expression.Convert(p, from), to), typeof(object)),
p).Compile();
}
private static readonly Dictionary<Tuple<Type, Type>, Func<object, object>> CastCache
= new Dictionary<Tuple<Type, Type>, Func<object, object>>();
public static Func<object, object> GetCastDelegate(Type from, Type to)
{
lock (CastCache)
{
var key = new Tuple<Type, Type>(from, to);
Func<object, object> 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 magia. De fundición no se produce en el código, como lo hace con la dynamic
de palabras clave, sólo los datos subyacentes del objeto se convierte. En el momento de la compilación, todavía tenemos que descubrir cuidadosamente qué tipo de objeto puede ser, haciendo que esta solución sea poco 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.
Claro que puedes aquí es a la vez una conversión simple (suponiendo que es una conversión de tipo T) y si es conveniente una conversión (supongamos que podemos convertir esto en una T):
public T CastExamp1<T>(object input) {
return (T) input;
}
public T ConvertExamp1<T>(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.
Por ejemplo:
Type intType = typeof(Int32);
object value1 = 1000.1;
object value2 = Convert.ChangeType(value1, intType);
// Variable value2 is now an Int32 with a value of 1000
He escrito la respuesta con genéricos, porque creo que es un signo muy probable de olor de código cuando se quiere convertir a something
en a something else
sin manejar un tipo real. Con interfaces adecuadas que no deberían ser necesarias el 99.9% de las veces. Quizás haya algunos casos de vanguardia en lo que respecta a la reflexión que podría tener sentido, pero recomendaría evitarlos.
Cuando se trata de casting para 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 de enumeración 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 casting podría verse así:
private static T GetEnum<T>(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));
}
Dejando de lado el boxeo y el desempaquetado por simplicidad, no hay una acción específica en tiempo de ejecución involucrada en el lanzamiento de la jerarquía de herencia. Es sobre todo una cosa de tiempo de compilación. Esencialmente, una conversión le dice al compilador que trate el valor de la variable como otro tipo.
¿Qué podrías hacer después del elenco? No conoces el tipo, por lo que no podrías llamar a ningún método. No habría nada especial que pudieras hacer. Específicamente, puede ser útil solo si conoce los posibles tipos en tiempo de compilación, conviértalo manualmente y maneje cada caso por separado con las instrucciones if
:
if (type == typeof(int)) {
int x = (int)obj;
DoSomethingWithInt(x);
} else if (type == typeof(string)) {
string s = (string)obj;
DoSomethingWithString(s);
} // ...
Otras respuestas no mencionan el tipo "dinámico". Entonces, para agregar una respuesta más, puede usar el tipo "dinámico" para almacenar el objeto resultante sin tener que convertir el objeto convertido con un tipo estático.
dynamic changedObj = Convert.ChangeType(obj, typeVar);
changedObj.Method();
Tenga en cuenta que con el uso de "dinámico" el compilador pasa por alto la verificación de tipos estáticos, lo que podría introducir posibles errores de tiempo de ejecución si no tiene cuidado.
Si necesita echar objetos en tiempo de ejecución sin saber el tipo de destino, puede utilizar la reflexión para hacer un convertidor dinámico.
Esta es una versión simplificada (sin método de almacenamiento en caché):
public static class Tool
{
public static object CastTo<T>(object value) where T : class
{
return value as T;
}
private static readonly MethodInfo CastToInfo = typeof (Tool).GetMethod("CastTo");
public static object DynamicCast(object source, Type targetType)
{
return CastToInfo.MakeGenericMethod(new[] { targetType }).Invoke(null, new[] { source });
}
}
entonces puedes llamarlo:
var r = Tool.DynamicCast(myinstance, typeof (MyClass));
aún más limpio:
public static bool TryCast<T>(ref T t, object o)
{
if (!(o is T))
{
return false;
}
t = (T)o;
return true;
}
public bool TryCast<T>(ref T t, object o)
{
if (
o == null
|| !typeof(T).IsAssignableFrom(o.GetType())
)
return false;
t = (T)o;
return true;
}