Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generic Type Converter - TypeConverter or Convert.ChangeType

Tags:

c#

I am trying to convert from a String a a 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?

like image 970
Miguel Moura Avatar asked Jun 24 '16 10:06

Miguel Moura


People also ask

What does convert ChangeType do?

ChangeType(Object, TypeCode) is a general-purpose conversion method that converts the object specified by value to a predefined type specified by typeCode . The value parameter can be an object of any type.

How to convert string into type c#?

Try: Type type = Type. GetType(inputString); //target type object o = Activator.

What is Typeconverter C#?

Provides a unified way of converting types of values to other types, as well as for accessing standard values and subproperties.


2 Answers

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.

like image 77
pijemcolu Avatar answered Oct 04 '22 06:10

pijemcolu


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)...

like image 43
György Kőszeg Avatar answered Oct 04 '22 07:10

György Kőszeg