Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

default(T) on reflected type

In browsing other answers, I have come up with the following extension method which works a treat:

public static T Convert<T>( this string input )
{
    var converter = TypeDescriptor.GetConverter( typeof( T ) );
    if ( converter != null )
    {
        try
        {
            T result = (T) converter.ConvertFromString( input );
            return result;
        }
        catch
        {
            return default( T );
        }
    }
    return default( T );
}

And I can use it like:

string s = "2011-09-21 17:45";
DateTime result = s.ConvertTo( typeof( DateTime ) );
if ( result == DateTime.MinValue )
    doSomethingWithTheBadData();

Awesome! Works great. Now, I'd like to do something similar with a reflected type. I have:

public static dynamic ConvertTo( this string input, Type type )
{
    var converter = TypeDescriptor.GetConverter( type );
    if ( converter != null )
    {
        try
        {
            dynamic result = converter.ConvertFromString( input );
            return ( result );
        }
        catch
        {
            return default( type );  // bogus
        }
    }

    return default( type );  // bogus
}

And I'd like to use it thus:

Type someType;  // will be DateTime, int, etc., but not known until runtime
DateTime result = s.ConvertTo( sometype );
if ( result == DateTime.MinValue )
    doSomethingWithTheBadData();

Of course, the compiler objects to the 'bogus' lines in the ConvertTo method. What I need (ok, don't necessarily need, but it'd be nice) is a way to get the same result as in the first example so that if the conversion fails, something that can be assigned to the reflected object is returned and can be recognized in the same manner as in the first example.

Edit:

What I finished with:

public static dynamic ConvertTo( this string input, Type type, out bool success )
{
    dynamic result;

    var converter = TypeDescriptor.GetConverter( type );
    if ( converter != null )
    {
        try
        {
            result = converter.ConvertFromString( input );
            success = true;
            return result;
        }
        catch { /* swallow the exception */ }
    }

    result = type.IsValueType ? Activator.CreateInstance( type ) : null;
    success = false;

    return result;
}

and used:

bool success;
string val = "2011-09-21 17:25";
dateTime = val.ConvertTo( typeof( DateTime ), out success );
if ( success )
    doSomethingGood();

val = "foo";
dateTime = val.ConvertTo( typeof( DateTime ), out success );
if ( !success )
    dealWithBadData();

Remembering that, for the purpose of demonstration, I'm hard-coding the typeof() bit. In my application, the types are all reflected.

Thanks to all for the speedy answers!

like image 882
BillP3rd Avatar asked Dec 06 '22 19:12

BillP3rd


2 Answers

You can use

//to get default(T) from an instance of Type
type.IsValueType ? Activator.CreateInstance(type) : null;

This is because value types are guaranteed to have a default constructor, and the default value of a reference type is a null.

like image 196
Cheng Chen Avatar answered Dec 28 '22 23:12

Cheng Chen


If you're passing in the type using typeof(Type), then obviously you could just use the first method. Assuming, then, that you're getting the type via reflection (which you say you are) then you can also use reflection to get the MethodInfo for your first version of Convert(), and then use MakeGenericMethod() to substitute your reflected type into it:

MethodInfo m = typeof(MyConvertExtensions).GetMethod("Convert");
MethodInfo invocable = m.MakeGenericMethod(myReflectedType);
invocable.Invoke(null, new[] { myString });
like image 30
dlev Avatar answered Dec 28 '22 23:12

dlev