2009-06-05 5 views
7

Je voudrais implémenter une fonction de conversion de type d'exécution à usage général qui utilise les convertisseurs de type .Net pour effectuer la conversion.Comment chercher et appeler un .Net TypeConverter pour un type particulier?

Est-ce que quelqu'un sait comment rechercher et invoquer un TypeConverter pour un type particulier?

Considérons cet exemple 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 n'utilisez pas 'dotnet' pour un tag. –

Répondre

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

Vous pouvez aussi regarder Convert.ChangeType(obj, destinationType)

+2

Je ne pense pas que Convert.ChangeType utilise des convertisseurs de type. – Patrik

+0

En outre, regardez Enum.ToObject si vous avez besoin de convertir un type intégral en un type énuméré réel. –

1

En plus de la réponse de Marc, vous pouvez considérer que le ViewState ASP.NET fait une fonction similaire à ce que vous Je demande à faire. Il essaie de trouver la conversion la plus efficace.

Il peut être utile de regarder this page et éventuellement this one aussi.

9

Voici le code utilisé dans l'une de nos applications existantes ... je ne sais pas si c'est idéal, mais cela fonctionne bien pour nous.

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

Il suffit d'appeler la méthode CustomTypeConversion et vous allez loin ... probablement un peu plus que vous avez besoin, mais être approfondie est pas un crime (ou est-ce?).

+3

Notez que les implémentations de TypeConverter peuvent être ajoutées au moment de l'exécution (via TypeDescriptor) - et le framework standard le récupérera - mais la réflexion (ci-dessus) * ne prendra pas * de telles additions; System.ComponentModel est conçu pour être très flexible au moment de l'exécution ... –

+0

Ah, bon ... cette question a été soulevée pour nous (encore) - ce code a été autour de notre application pendant un certain temps; C'est bon d'avoir un nouvel ensemble d'yeux. Merci! –

+0

Pour être honnête, dans la plupart des cas vous ne verriez jamais la différence ... il n'est pas * commun * que les gens commencent à ajouter des convertisseurs/descripteurs d'exécution. Mais c'est possible (j'ai un exemple sur stackoverflow quelque part ...) –

1

Je ne sais pas comment il est robuste, mais je l'utilise parfois ce code pour la conversion de type générique:

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

Je ne sais pas si la méthode changeType utilisation TypeConverters ...

Questions connexes