2009-06-05 11 views
7

Me gustaría implementar una función de conversión de tipo de tiempo de ejecución de uso general que utilice .Net TypeConverters para hacer la conversión.¿Cómo buscar e invocar un .NET TypeConverter para un tipo particular?

¿Alguien sabe cómo buscar e invocar un TypeConverter para un tipo particular?

Considere este ejemplo de C#:

// 
// Convert obj to the type specified by 'toType'. 
// 
object ConvertTo(object obj, Type toType) 
{ 
    if (TypeIsEqualOrDerivesFrom(obj.GetType(), toType)) <-- I know how to implement this. 
    { 
     // The type of obj is the same as the type specified by 'toType' or 
     // the type of obj derives from the type specified by 'toType'. 
     return obj; 
    } 

    if (TypeConverterExists(obj.GetType(), toType) <-- How do I implement this? 
    { 
     // There exists a type convertor that is capable of converting from 
     // the type of obj to the type specified by 'toType'. 
     return InvokeTypeConverter(obj, toType); <-- How do I implement this? 
    } 

    throw new TypeConversionFailedException(); 
} 
+0

Don 't use' dotnet 'para una etiqueta. –

Respuesta

31
TypeConverter converter = TypeDescriptor.GetConverter(sourceType); 
    if(converter.CanConvertTo(destinationType)) { 
     return converter.ConvertTo(obj, destinationType); 
    } 
    converter = TypeDescriptor.GetConverter(destinationType); 
    if(converter.CanConvertFrom(sourceType)) { 
     return converter.ConvertFrom(obj); 
    } 

También podría mirar a Convert.ChangeType(obj, destinationType)

+2

No creo que Convert.ChangeType use convertidores de tipo. – Patrik

+0

Además, consulte Enum.ToObject si necesita convertir un tipo integral a un tipo enumerado real. –

1

Además de la respuesta de Marc, es posible considerar que ViewState de ASP.NET hace una función similar a lo que estás pidiendo que hagas Intenta encontrar la conversión más eficiente.

Puede valer la pena mirar this page y posiblemente this one también.

9

Aquí está el código utilizado en una de nuestras aplicaciones existentes ... no estoy seguro de si es ideal pero funciona bien para nosotros.

/// <summary> 
/// Attempts to convert a value using any customer TypeConverters applied to the member 
/// </summary> 
/// <param name="value">Object containing the value to be assigned</param> 
/// <param name="member">Member to be assigned to</param> 
/// <returns><paramref name="value"/> converted to the appropriate type</returns> 
public static Object CustomTypeConversion (object value, MemberInfo member) 
{ 
    if (value == null || value == DBNull.Value) 
     return value; 

    if (member == null) 
     throw new ArgumentNullException (); 

    List<TypeConverter> converters = GetCustomTypeConverters (member); 

    foreach (TypeConverter c in converters) 
    { 
     if (c.CanConvertFrom (value.GetType ())) 
      return c.ConvertFrom (value); 
    } 

    if (member is PropertyInfo) 
    { 
     PropertyInfo prop = member as PropertyInfo; 
     return ConvertToNative(value , prop.PropertyType); 
    } 
    return ConvertToNative (value, member.MemberType.GetType ()); 
} 

/// <summary> 
/// Extracts and instantiates any customer type converters assigned to a 
/// derivitive of the <see cref="System.Reflection.MemberInfo"/> property 
/// </summary> 
/// <param name="member">Any class deriving from MemberInfo</param> 
/// <returns>A list of customer type converters, empty if none found</returns> 
public static List<TypeConverter> GetCustomTypeConverters (System.Reflection.MemberInfo member) 
{ 
    List<TypeConverter> result = new List<TypeConverter>(); 

    try 
    { 
     foreach (TypeConverterAttribute a in member.GetCustomAttributes(typeof(TypeConverterAttribute) , true)) 
     { 
      TypeConverter converter = Activator.CreateInstance(Type.GetType(a.ConverterTypeName)) as TypeConverter; 

      if (converter != null) 
       result.Add(converter); 
     } 
    } 
    catch 
    { 
     // Let it go, there were no custom converters 
    } 

    return result; 
} 

/// <summary> 
/// Attempts to cast the incoming database field to the property type 
/// </summary> 
/// <param name="value">Database value to cast</param> 
/// <param name="castTo">Type to cast to</param> 
/// <returns>The converted value, if conversion failed the original value will be returned</returns> 
public static object ConvertToNative (object value , Type castTo) 
{ 
    try 
    { 
     return Convert.ChangeType(value , castTo , System.Threading.Thread.CurrentThread.CurrentCulture); 
    } 
    catch 
    { 
     return value; 
    } 
} 

Sólo tiene que llamar al método CustomTypeConversion y ya está ... probablemente un poco más de lo necesario, pero siendo a fondo no es un delito (o es?).

+3

Tenga en cuenta que las implementaciones de TypeConverter se pueden agregar en el tiempo de ejecución (a través de TypeDescriptor) y el marco estándar lo recogerá, pero la reflexión (arriba) * no recogerá esas adiciones; System.ComponentModel está diseñado para ser muy flexible en el tiempo de ejecución ... –

+0

Ah, bueno ... ese problema ha surgido para nosotros (todavía) - este código ha estado en nuestra aplicación por un tiempo; es bueno tener un nuevo par de ojos para revisarlo. ¡Gracias! –

+0

Para ser honesto, en la mayoría de los casos, nunca verá la diferencia ... no es * tan * común que las personas comiencen a agregar convertidores/descriptores de tiempo de ejecución. Pero es posible (tengo un ejemplo en stackoverflow en alguna parte ...) –

1

No sé lo robusto que es, pero a veces uso el código de conversión de tipo genérico:

public T ConvertTo<T>(object value) 
{ 
    return (T)Convert.ChangeType(value, typeof(T)); 
} 

no sé si los TypeConverters uso del método changetype ...

Cuestiones relacionadas