2009-06-05 6 views
7

Vorrei implementare una funzione di conversione di tipo runtime per scopi generici che utilizza .Net TypeConverters per eseguire la conversione.Come cercare e richiamare un TypeConverter .Net per un tipo particolare?

Qualcuno sa come cercare e invocare un TypeConverter per un tipo particolare?

Si consideri questo esempio 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 usare 'dotnet' per un tag. –

risposta

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); 
    } 

Si potrebbe anche guardare Convert.ChangeType(obj, destinationType)

+2

Non penso che Convert.ChangeType utilizzi i convertitori di tipi. – Patrik

+0

Inoltre, consultare Enum.ToObject se è necessario convertire un tipo integrale in un tipo enumerato effettivo. –

1

Oltre alla risposta di Marc, si potrebbe considerare che il ViewState di ASP.NET fa una funzione simile a quello che si Chiedo di fare. Cerca di trovare la conversione più efficiente.

Potrebbe valere la pena dare un'occhiata a this page e possibilmente anche this one.

9

Ecco il codice utilizzato in una delle nostre app esistenti ... non so se sia l'ideale ma funziona bene per noi.

/// <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; 
    } 
} 

Basta chiamare il metodo CustomTypeConversion e si va via ... probabilmente un altro po ' del necessario, ma di essere approfondita non è un crimine (o è?).

+3

Nota che le implementazioni di TypeConverter possono essere aggiunte in fase di esecuzione (tramite TypeDescriptor) - e il framework standard lo rileverà - ma il reflection (sopra) * non * preleverà tali aggiunte; System.ComponentModel è progettato per essere molto flessibile in fase di esecuzione ... –

+0

Ah, bene ... il problema è venuto fuori per noi (ancora) - questo codice è stato in giro per la nostra app per un po '; è bello avere una nuova serie di occhi rivederlo. Grazie! –

+0

Per essere onesti, nella maggior parte dei casi non si vedrebbe mai la differenza ... non è * che * comune che le persone inizino ad aggiungere convertitori/descrittori di runtime. Ma è possibile (ho un esempio su StackOverflow da qualche parte ...) –

1

Non so come robusto è, ma io a volte uso questo codice per la conversione di tipo generico:

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

non so se l'utilizzazione TypeConverters metodo ChangeType ...

Problemi correlati