Frage

Wie kann ich mit Reflection in eine Nullable von einer Zeichenfolge konvertieren?

Ich habe den folgenden Code, um in fast jeden Wert auf fast jeden Wert zu konvertieren. Es gibt einiges darüber, dass der Code den Issidesignable von usw. verwendet wird. Dies ist also der letzte Ausweg.

MethodInfo parse = t.GetMethod("Parse", new Type[] { typeof(string) });

if (parse != null)
{
    object parsed = parse.Invoke(null, new object[] { value.ToString() });
    return (T)parsed;
}
else
{
    throw new InvalidOperationException("The value you specified is not a valid " + typeof(T).ToString());
}

Das Problem kommt, wenn ich mich wie lang in einen nullierbaren Typ konvertieren möchte.

Offensichtlich das lange? Die Klasse hat keine Parse -Methode.

Wie extrahiere ich die Parse -Methode aus den Nullable's's's Schablone Typ?

BEARBEITEN:

Hier ist eine kurze Batterie von Tests, die ich bestehen möchte:

[Test]
public void ConverterTNullable()
{
    Assert.That((int?)1, Is.EqualTo(Converter<int?>.Convert(1)));
    Assert.That((int?)2, Is.EqualTo(Converter<int?>.Convert(2.0d)));
    Assert.That(3, Is.EqualTo(Converter<long>.Convert(3)));

    Assert.That((object)null, Is.EqualTo(Converter<long?>.Convert("")));
    Assert.That((object)null, Is.EqualTo(Converter<long?>.Convert(null)));
    Assert.That((object)null, Is.EqualTo(Converter<long?>.Convert(DBNull.Value)));

    Assert.That((long)1, Is.EqualTo(Converter<long?>.Convert("1")));
    Assert.That((long)2, Is.EqualTo(Converter<long?>.Convert(2.0)));
    Assert.That((long?)3, Is.EqualTo(Converter<long>.Convert(3)));
}

Und die ganze Funktion:

/// <summary>
/// Converts any compatible object to an instance of T.
/// </summary>
/// <param name="value">The value to convert.</param>
/// <returns>The converted value.</returns>
public static T Convert(object value)
{
    if (value is T)
    {
        return (T)value;
    }

    Type t = typeof(T);

    if (t == typeof(string))
    {
        if (value is DBNull || value == null)
        {
            return (T)(object)null;
        }
        else
        {
            return (T)(object)(value.ToString());
        }
    }
    else
    {
        if (value is DBNull || value == null)
        {
            return default(T);
        }

        if (value is string && string.IsNullOrEmpty((string)value))
        {
            return default(T);
        }

        try
        {
            return (T)value;
        }
        catch (InvalidCastException)
        {
        }

        if (Nullable.GetUnderlyingType(t) != null)
        {
            t = Nullable.GetUnderlyingType(t);
        }

        MethodInfo parse = t.GetMethod("Parse", new Type[] { typeof(string) });

        if (parse != null)
        {
            object parsed = parse.Invoke(null, new object[] { value.ToString() });
            return (T)parsed;
        }
        else
        {
            throw new InvalidOperationException("The value you specified is not a valid " + typeof(T).ToString());
        }
    }
}
War es hilfreich?

Lösung 3

Ich habe dieses kleine bisschen hinzugefügt:

if (Nullable.GetUnderlyingType(t) != null)
{
    t = Nullable.GetUnderlyingType(t);
}

MethodInfo parse = t.GetMethod("Parse", new Type[] { typeof(string) });

Danke an alle!

Andere Tipps

Ich würde wahrscheinlich das verwenden TypeConverter in diesem Fall, und Nullable.GetUnderlyingType(); Beispiel auf dem Weg ...

    static void Main()
    {
        long? val1 = Parse<long?>("123");
        long? val2 = Parse<long?>(null);
    }

    static T Parse<T>(string value)
    {
        return (T) TypeDescriptor.GetConverter(typeof(T))
            .ConvertFrom(value);
    }

Dies sollte zum Job. (Der Code ist zur Einfachheit in eine Erweiterungsmethode eingebettet, obwohl dies möglicherweise nicht das ist, was Sie wollen.)

public static T? ParseToNullable<T>(this string value) where T : struct
{
    var parseMethod = typeof(T).GetMethod("Parse", new Type[] { typeof(string) });
    if (parseMethod == null)
        return new Nullable<T>();

    try
    {
        var value = parseMethod.Invoke(null, new object[] { value.ToString() });
        return new Nullable<T>((T)value);
    }
    catch
    {
        return new Nullable<T>();
    }
}

Wenn Sie nun den generischen Typparamter möchten selbst Um der nicht zugrunde liegende Typ zu sein (ich sehe darin keinen Vorteil), können Sie nutzen:

Nullable.GetUnderlyingType(typeof(T))

Wie Marc Gravell vorschlug, würde es nur wenige geringfügige Änderungen am Code erfordern.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top