2016-06-24 23 views
6

Ich versuche, von einem String einen generischen Typ zu konvertieren. Der generische Typ wird ein Int32, Int64, Boolean, Double und so weiter ... Ich habe versucht, zwei Ansätze:Generischer Typ Konverter - TypeConverter oder Convert.ChangeType

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; 

    } 

} 

Die zweite ist allgemein wie es eine Aufgabe übernimmt.

Ich überlege auch, einen IFormatProvider in TryChangeType zu übergeben, der in Convert.ChangeType verwendet werden würde, um Kulturprobleme zu lösen und so weiter.

Halten Sie den zweiten Ansatz für besser?

Wie kann ich meinen Code verbessern?

+0

Mögliches Duplikat von [TypeConverter vs. Convert vs. TargetType.Parse] (http://stackoverflow.com/questions/7010669/typeconverter-vs-convert-vs-targettype-parse) –

Antwort

2

Im ersten Beispiel von Ihnen können Sie den try catch Block loswerden, indem Sie vorher CanConvertTo() und CanConvertFrom() anrufen.

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); 
     returns false; 
    } 
} 

Im zweiten Beispiel, warum es nicht noch generischer machen und in einem generischen Typ übergeben?

Convert funktioniert nur, wenn der Typ die Schnittstelle IConvertible implementiert, so können Sie dafür überprüfen, auf der anderen Seite stellt es noch nicht sicher, dass die Konvertierung möglich ist.

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

Es wäre schön, um nur die Ausnahmen fangen Sie wissen:

  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 
     } 

Dies könnte die Frage nicht vollständig beantworten, aber Sie für mögliche Verbesserungen wurden gefragt, so dachte ich, warum nicht.

+0

Ja, das macht noch mehr generisch. Guter Vorschlag. –

0

In Ihrem ersten Beispiel TypeDescriptor.GetConverter(Type) kann Ausnahmen auslösen, also verschieben Sie das in den try-Block. Ohne sie persönlich auszuprobieren, gefällt mir der zweite Weg.

This post zeigt ein Beispiel für das Testen auf Konvertierbarkeit ohne Try/Catch und Ansprüche Leistungsvorteile.

+0

Interessant ... Den Try Catch-Block loszuwerden war etwas, was ich machen wollte ... Ich wusste nicht, dass es möglich war. –

1

Die zweite ist nur für IConvertible Typen anwendbar. Wenn das ist, was Sie wollen, können Sie eine Einschränkung anwenden, auch (ChangeType wird eine Ausnahme für nicht wandlungsfähige Typen sowieso werfen):

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

Die erste allgemeinere ist, wird TypeConverter verwendet, wenn die. NET-Komponentenmodell sollte verwendet werden. In Designer werden z. B. Typkonverter verwendet, um die Werte aus der Zeichenfolge im Eigenschaftenraster zu konvertieren. Aber Sie sollten eine kleine zusätzliche Prüfung hier hinzufügen, auch:

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

Zusätzlich würde ich erwähnen, dass Sie die ConvertFromInvariantString Methode verwenden sollten, wenn Sie (falls nicht mit den anderen Bereich Einstellungen Probleme wollen Punktwerte des Schwebens, zum Beispiel) ...

+0

Über die ConvertFromInvariantString, das ist ein guter Tipp ... Ich hatte Probleme mit der Konvertierung von Doppel mit "." oder "," ... Aber mit der zweiten Option könnte ich einen IFormatProvider übergeben ... Das löst das Problem im zweiten Beispiel, oder? –

+0

Ja, die Verwendung einer bestimmten Kultur löst das Problem auch. Übrigens können Sie auch hier von jeder "Objekt" Quelle konvertieren. Verwenden Sie einfach die 'CanConvertFrom (Type)' Methode. – taffer