Как искать и вызывать .Net TypeConverter для определенного типа? - PullRequest
9 голосов
/ 05 июня 2009

Я хотел бы реализовать универсальную функцию преобразования типов во время выполнения, которая использует .Net TypeConverters для выполнения преобразования.

Кто-нибудь знает, как искать и вызывать TypeConverter для определенного типа?

Рассмотрим пример 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();
}

Ответы [ 4 ]

34 голосов
/ 05 июня 2009
    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);
    }

Вы также можете посмотреть на Convert.ChangeType(obj, destinationType)

10 голосов
/ 05 июня 2009

Вот код, используемый в одном из наших существующих приложений ... не уверен, что он идеален, но он хорошо работает для нас.

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

Просто вызовите метод CustomTypeConversion, и вы получите ... вероятно, немного больше, чем вам нужно, но тщательность - не преступление (или это?)

1 голос
/ 05 июня 2009

Я не знаю, насколько он устойчив, но иногда я использую этот код для преобразования универсального типа:

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

Я не знаю, использует ли метод ChangeType TypeConverters ...

1 голос
/ 05 июня 2009

В дополнение к ответу Марка вы можете подумать, что ViewState в ASP.NET выполняет функцию, аналогичную той, которую вы просите. Он пытается найти наиболее эффективное преобразование.

Возможно, стоит взглянуть на эту страницу и, возможно, эту тоже.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...