Generische Typkonvertierung FROM Zeichenfolge


234

Ich habe eine Klasse, mit der ich "Eigenschaften" für eine andere Klasse speichern möchte. Diese Eigenschaften haben einfach einen Namen und einen Wert. Im Idealfall möchte ich typisierte Eigenschaften hinzufügen können , damit der zurückgegebene "Wert" immer von dem Typ ist, den ich möchte.

Der Typ sollte immer ein Grundelement sein. Diese Klasse unterklassifiziert eine abstrakte Klasse, in der Name und Wert grundsätzlich als Zeichenfolge gespeichert sind. Die Idee ist, dass diese Unterklasse der Basisklasse eine gewisse Typensicherheit hinzufügt (und mich bei einigen Konvertierungen erspart).

Also habe ich eine Klasse erstellt, die (ungefähr) so lautet:

public class TypedProperty<DataType> : Property
{
    public DataType TypedValue
    {
        get { // Having problems here! }
        set { base.Value = value.ToString();}
    }
}

Die Frage ist also:

Gibt es eine "generische" Möglichkeit, von einem String zurück in ein Grundelement zu konvertieren?

Ich kann anscheinend keine generische Schnittstelle finden, die die Konvertierung auf der ganzen Linie verknüpft (so etwas wie ITryParsable wäre ideal gewesen!).


Es würde mich interessieren, ein Beispiel Ihrer konkreten Klasse zu sehen, sogar nur einen Ausschnitt. :)
Jon Limjap

Können Sie bitte die relevanten Teile Ihrer Basisklasse posten?
JJS

Ich frage mich, ob jemand die Antworten hier in .Net Standard 1.2 bekommen kann: /
Dan Rayson

Antworten:


374

Ich bin nicht sicher, ob ich Ihre Absichten richtig verstanden habe, aber mal sehen, ob dies hilft.

public class TypedProperty<T> : Property where T : IConvertible
{
    public T TypedValue
    {
        get { return (T)Convert.ChangeType(base.Value, typeof(T)); }
        set { base.Value = value.ToString();}
    }
}

Ich habe mich seit einigen Tagen gefragt, wie ich einen Stream in einen generischen Typ deserialisieren kann. Danke :)
Falle

3
Ich stimme zu, obwohl Convert.ChangeTypees keine sehr universelle und erweiterbare Lösung ist, funktioniert es für die meisten Basistypen. Wenn etwas Besseres benötigt wird, ist es kein Problem, diese Methode in etwas Größeres zu verpacken, wie es Tim vorgeschlagen hat, oder eine andere Konvertierungsmethode zu verwenden.
Lubos Hasko

18
Ich würde definitiv hinzufügen, wo T: IConvertible
MikeT

5
Typ T sollte nicht IConvertible sein, aber Typ der Basis. Wert sollte.
Chapluck

74

Die Methode von lubos hasko schlägt für nullables fehl. Die folgende Methode funktioniert für Nullables. Ich habe es mir aber nicht ausgedacht. Ich habe es über Google gefunden: http://web.archive.org/web/20101214042641/http://dogaoztuzun.com/post/C-Generic-Type-Conversion.aspx Gutschrift für "Tuna Toksoz"

Verwendung zuerst:

TConverter.ChangeType<T>(StringValue);  

Die Klasse ist unten.

public static class TConverter
{
    public static T ChangeType<T>(object value)
    {
        return (T)ChangeType(typeof(T), value);
    }

    public static object ChangeType(Type t, object value)
    {
        TypeConverter tc = TypeDescriptor.GetConverter(t);
        return tc.ConvertFrom(value);
    }

    public static void RegisterTypeConverter<T, TC>() where TC : TypeConverter
    {

        TypeDescriptor.AddAttributes(typeof(T), new TypeConverterAttribute(typeof(TC)));
    }
}

Ich würde eine Fallback-Konvertierungsoption für Enums und andere komplexe Strukturen hinzufügen, aber einen guten Aufruf.
Tomer W

2
Warum der RegisterTypeConverter? Müssen wir die Konverter vorher registrieren? (Leider ist der Link tot, so dass ich ihn nicht nachlesen konnte)
Cohen

Für mehrere Conversions sollten Sie tc(die TypeConverter) wahrscheinlich nur einmal erstellen . TypeConverterist langsam, weil es Reflexion verwendet, um nach dem zu suchen TypeConverterAttribute. Wenn Sie ein einzelnes privates TypeConverterFeld initialisieren , sollten Sie es TypeConverterviele Male wiederverwenden können .
Kevin P. Rice

Funktioniert gut, aber wenn T ein ist object, wird eine Ausnahme ausgelöst. Ich konnte dies umgehen, indem ich `if (typeof (T) .IsPrimitive) {return TConverter.ChangeType <T> (StringValue); } else {object o = (object) StringValue; zurückkommen zu; } `als Ersatz für das Verwendungsbeispiel TConverter.ChangeType<T>(StringValue)
Matt

14

Für viele Typen (Integer, Double, DateTime usw.) gibt es eine statische Parse-Methode. Sie können es mit Reflection aufrufen:

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

if (m != null)
{
    return m.Invoke(null, new object[] { base.Value });
}

8
TypeDescriptor.GetConverter(PropertyObject).ConvertFrom(Value)

TypeDescriptorist eine Klasse mit einer Methode, GetConvertordie ein TypeObjekt akzeptiert. Anschließend können Sie eine ConvertFromMethode aufrufen , um die valuefür das angegebene Objekt zu konvertieren .


Ich persönlich denke, diese Schnittstelle ist besser für die Konvertierung geeignet als die Methode Convert.ChangeType, da Sie die IConvertible-Schnittstelle für alle Ihre Klassen implementieren müssen.
Sauleil

3

Sie könnten möglicherweise ein Konstrukt wie eine Merkmalsklasse verwenden . Auf diese Weise hätten Sie eine parametrisierte Hilfsklasse, die weiß, wie eine Zeichenfolge in einen Wert ihres eigenen Typs konvertiert wird. Dann könnte Ihr Getter so aussehen:

get { return StringConverter<DataType>.FromString(base.Value); }

Nun muss ich darauf hinweisen, dass meine Erfahrung mit parametrisierten Typen auf C ++ und seine Vorlagen beschränkt ist, aber ich stelle mir vor, dass es eine Möglichkeit gibt, mit C # -Generika dasselbe zu tun.


Die generischen Versionen sind in C # nicht vorhanden.
Shimmy Weitzhandler

3

Überprüfen Sie die statische Aufladung Nullable.GetUnderlyingType. - Wenn der zugrunde liegende Typ null ist, ist der Vorlagenparameter nicht null, Nullableund wir können diesen Typ direkt verwenden. - Wenn der zugrunde liegende Typ nicht null ist, verwenden Sie den zugrunde liegenden Typ bei der Konvertierung.

Scheint für mich zu arbeiten:

public object Get( string _toparse, Type _t )
{
    // Test for Nullable<T> and return the base type instead:
    Type undertype = Nullable.GetUnderlyingType(_t);
    Type basetype = undertype == null ? _t : undertype;
    return Convert.ChangeType(_toparse, basetype);
}

public T Get<T>(string _key)
{
    return (T)Get(_key, typeof(T));
}

public void test()
{
    int x = Get<int>("14");
    int? nx = Get<Nullable<int>>("14");
}

1

Inspiriert von der Antwort von Bob unterstützen diese Erweiterungen auch die Nullwertkonvertierung und alle primitiven Konvertierungen zurück und viertens.

public static class ConversionExtensions
{
        public static object Convert(this object value, Type t)
        {
            Type underlyingType = Nullable.GetUnderlyingType(t);

            if (underlyingType != null && value == null)
            {
                return null;
            }
            Type basetype = underlyingType == null ? t : underlyingType;
            return System.Convert.ChangeType(value, basetype);
        }

        public static T Convert<T>(this object value)
        {
            return (T)value.Convert(typeof(T));
        }
}

Beispiele

            string stringValue = null;
            int? intResult = stringValue.Convert<int?>();

            int? intValue = null;
            var strResult = intValue.Convert<string>();

0
public class TypedProperty<T> : Property
{
    public T TypedValue
    {
        get { return (T)(object)base.Value; }
        set { base.Value = value.ToString();}
    }
}

Ich benutze die Konvertierung über ein Objekt. Es ist ein bisschen einfacher.


danke Ich muss ein T in eine Schnittstelle konvertieren und das einfache Konvertierungs-T-Objekt funktioniert korrekt, einfach und schnell. Danke
LXG

5
(int) (Objekt) "54"; ist eine FATALITÄT!, das ist nicht VB!
Tomer W

0

Ich habe Lobos Antwort verwendet und es funktioniert. Aber ich hatte ein Problem mit der Umwandlung von verdoppelt wegen der Kultureinstellungen. Also habe ich hinzugefügt

return (T)Convert.ChangeType(base.Value, typeof(T), CultureInfo.InvariantCulture);

0

Noch eine Variation. Behandelt Nullables sowie Situationen, in denen die Zeichenfolge null und T nicht nullable ist.

public class TypedProperty<T> : Property where T : IConvertible
{
    public T TypedValue
    {
        get
        {
            if (base.Value == null) return default(T);
            var type = Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T);
            return (T)Convert.ChangeType(base.Value, type);
        }
        set { base.Value = value.ToString(); }
    }
}

0

Sie können dies in einer Zeile wie folgt tun:

YourClass obj = (YourClass)Convert.ChangeType(YourValue, typeof(YourClass));

Viel Spaß beim Codieren;)


Wenn Sie Code als Antwort freigegeben haben, versuchen Sie bitte, ihn zu erklären.
Yunus Temurlenk
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.