简体   繁体   中英

Generic Type Converter - TypeConverter or Convert.ChangeType

I am trying to convert from a String aa generic type. The generic type will be an Int32, Int64, Boolean, Double and so on ... I tried two approaches:

public static Boolean TryParse<T>(String source, out T value) {

  TypeConverter converter = TypeDescriptor.GetConverter(typeof(T));

  try {

    value = (T)converter.ConvertFromString(source);
    return true;

  } catch {

    value = default(T);
    return false;

  }

}

public static Boolean TryChangeType<T>(Object source, out T value) {

  try {

    Type type = Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T);

    value = (T)Convert.ChangeType(source, type);
    return true;

  } catch {

    value = default(T);
    return false;

  }

}

The second one is more generic as it accepts an Object.

I am also considering passing an IFormatProvider in TryChangeType that would be used in Convert.ChangeType to resolve Culture issues and so on.

Do you consider the second approach better?

Any way I can improve my code?

In the first example of yours you can get rid of the try catch block by calling CanConvertTo() and CanConvertFrom() beforehand.

public static bool TryParse<T>(string source, out T value)
{
    TypeConverter converter = TypeDescriptor.GetConverter(typeof (T));
    if (converter.CanConvertTo(typeof (T)) && converter.CanConvertFrom(typeof (string)))
    {
        value = (T)converter.ConvertFromString(source);
        return true;
    }
    else
    {
        value = default (T);
        return false;
    }
}

In the second example why not make it even more generic and pass in a generic type?

Convert only works if the type implements the interface IConvertible so you can check for that, on the other hand it stil doesn't ensure that the conversion will be possible.

        public static bool TryChangeType<T, TR>(T input, out TR output) where T : IConvertible
    {
        bool result = false;
        try
        {
            Type type = Nullable.GetUnderlyingType(typeof(TR));
            output = (TR)Convert.ChangeType(input, type);
            result = true;
        }
        catch(Exception)
        {
            output = default(TR);
        }
        return result;
    }

It would be nice to only catch the exceptions you know of:

            catch(InvalidCastException)
        {
            output = default(TR);
            //Conversion is not unsupported
        }
            catch(FormatException)
        {
            output = default(TR);
            //string input value was in incorrect format
        }
            catch(InvalidCastException)
        {
            output = default(TR);
            //Conversion is not unsupported
        }
            catch(OverflowException)
        {
            output = default(TR);
            //narrowing conversion between two numeric types results in loss of data
        }

This might not answer the question fully, but you were asking for possible improvements so I thought why not.

The second one is applicable only for IConvertible types. If this is what you want, you might want to apply a constraint, too ( ChangeType will throw an exception for non-convertible types anyway):

public static Boolean TryChangeType<T>(Object source, out T value)
    where T : IConvertible
{
    // ...
}

The first one is more general, TypeConverter is used when the .NET component model should be used. For example, in designers, type converters are used to convert the values from string in the property grid. But you should add a small additional check here, too:

if (!converter.CanConvertFrom(typeof(string)))
    return false;

Additionally, I would mention that you should use the ConvertFromInvariantString method if you do not want trouble with the different region settings (in case of floating point values, for example)...

In your first example TypeDescriptor.GetConverter(Type) can throw exceptions, so move that into the try block. Without trying them personally, out of your two approaches I like the second one.

This post shows an example of testing for convertibility with no try/catch and claims performance benefits.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM