2009-06-05 9 views
7

Chciałbym zaimplementować funkcję konwersji typu ogólnego wykonywania, która używa .Net TypeConverters do konwersji.Jak wyszukiwać i wywoływać .Net TypeConverter dla określonego typu?

Czy ktoś wie, jak wyszukać i wywołać TypeConverter dla określonego typu?

Rozważmy C# przykład:

// 
// 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 do tagu użyj 'dotnet'. –

Odpowiedz

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

Można również spojrzeć na Convert.ChangeType(obj, destinationType)

+2

Nie sądzę, że Convert.ChangeType używa typu konwertery. – Patrik

+0

Zobacz także Enum.ToObject, jeśli potrzebujesz konwertera typu integralnego do rzeczywistego typu wyliczeniowego. –

1

Oprócz odpowiedź Marca, można uznać, że ViewState ASP.NET za robi podobną funkcję do tego, co "proszę o zrobienie. Stara się znaleźć najbardziej wydajną konwersję.

Warto również rzucić okiem na this page i prawdopodobnie this one.

9

Oto kod używany w jednej z naszych istniejących aplikacji ... nie wiem, czy jest idealny, ale działa dobrze dla nas.

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

Wystarczy wywołać metodę CustomTypeConversion i idziesz dalej ... prawdopodobnie bardziej trochę niż trzeba, ale jest dokładne nie jest przestępstwem (lub nie?).

+3

Zauważ, że implementacje TypeConverter można dodawać w czasie wykonywania (poprzez TypeDescriptor) - i standardowa struktura będzie je wybierać - ale odbicie (powyżej) * nie * pobudzi takich dodatków; System.ComponentModel został zaprojektowany tak, aby był bardzo elastyczny w czasie wykonywania ... –

+0

Ach, dobry ... ten problem pojawił się u nas (jeszcze) - ten kod był przez jakiś czas w pobliżu naszej aplikacji; dobrze jest mieć cały zestaw oczu, żeby to sprawdzić. Dzięki! –

+0

Szczerze mówiąc, w większości przypadków nigdy nie zobaczysz różnicy ... nie jest to * powszechne, że ludzie zaczynają dodawać konwertery/deskryptory środowiska wykonawczego. Ale jest to możliwe (mam przykład na stackoverflow gdzieś ...) –

1

Nie wiem, jak to jest solidna, ale czasami użyć tego kodu do konwersji typu rodzajowego:

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

Nie wiem, czy metoda changetype użytku TypeConverters ...

Powiązane problemy