Conversione di tipo generico DA stringa


234

Ho una classe che voglio usare per memorizzare "proprietà" per un'altra classe. Queste proprietà hanno semplicemente un nome e un valore. Idealmente, ciò che vorrei è poter aggiungere proprietà tipizzate , in modo che il "valore" restituito sia sempre del tipo che voglio che sia.

Il tipo dovrebbe essere sempre un primitivo. Questa classe subclasse una classe astratta che sostanzialmente memorizza il nome e il valore come stringa. L'idea è che questa sottoclasse aggiungerà un po 'di sicurezza del tipo alla classe base (oltre a salvarmi su qualche conversione).

Quindi, ho creato una classe che è (approssimativamente) questa:

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

Quindi la domanda è:

Esiste un modo "generico" per convertire da stringa a una primitiva?

Non riesco a trovare alcuna interfaccia generica che colleghi la conversione su tutta la linea (qualcosa come ITryParsable sarebbe stato l'ideale!).


Sarei interessato a vedere un esempio della tua classe concreta, anche solo uno snippet. :)
Jon Limjap,

puoi pubblicare le parti pertinenti della tua classe base?
JJS,

Mi chiedo se qualcuno può ottenere le risposte qui lavorando in. Net Standard 1.2: /
Dan Rayson

Risposte:


374

Non sono sicuro di aver capito bene le tue intenzioni, ma vediamo se questo aiuta.

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

Mi chiedo da alcuni giorni come deserializzare un flusso in un tipo generico. Grazie :)
Trappola

3
Sono d'accordo, sebbene Convert.ChangeTypenon sia una soluzione molto universale ed estensibile, funziona per la maggior parte dei tipi di base. se è necessario qualcosa di meglio, non è un problema avvolgere questo metodo in qualcosa di più grande come suggerito da Tim o utilizzare del tutto un metodo di conversione diverso.
lubos hasko,

18
Aggiungerei sicuramente il T: IConvertible
MikeT del

5
Il tipo T non dovrebbe essere IConvertible, ma il tipo di base. Il valore dovrebbe.
Chapluck,

74

Il metodo di lubos hasko fallisce per nullable. Il metodo seguente funzionerà per nullable. Non mi è venuto in mente, però. L'ho trovato tramite Google: http://web.archive.org/web/20101214042641/http://dogaoztuzun.com/post/C-Generic-Type-Conversion.aspx Credito a "Tuna Toksoz"

Primo utilizzo:

TConverter.ChangeType<T>(StringValue);  

La lezione è sotto.

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

aggiungerei opzioni di conversione Fallback per Enum e altre strutture complesse, ma buona chiamata.
Tomer W,

2
Perché RegisterTypeConverter? Dobbiamo prima registrare i convertitori? (sfortunatamente il link è morto, quindi non sono riuscito a leggerlo)
Cohen,

Per più conversioni dovresti probabilmente creare tc(il TypeConverter) una sola volta. TypeConverterè lento perché utilizza la riflessione per cercare il file TypeConverterAttribute. Se si inizializza un singolo TypeConvertercampo privato , si dovrebbe essere in grado di riutilizzare TypeConverterpiù volte.
Kevin P. Rice,

Funziona bene, ma se T è un object, genera un'eccezione. Sono stato in grado di risolvere il problema utilizzando `if (typeof (T) .IsPrimitive) {return TConverter.ChangeType <T> (StringValue); } else {object o = (object) StringValue; Ritornare a; } `in sostituzione del campione di utilizzo TConverter.ChangeType<T>(StringValue)
Matt,

14

Per molti tipi (intero, doppio, DateTime ecc.), Esiste un metodo Parse statico. Puoi invocarlo usando reflection:

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)

TypeDescriptorè una classe con metodo GetConvertorche accetta un Typeoggetto e quindi è possibile chiamare il ConvertFrommetodo per convertire l' valueoggetto specificato.


Personalmente ritengo che questa interfaccia sia migliore per gestire la conversione anziché il metodo Convert.ChangeType poiché è necessario implementare l'interfaccia IConvertible su tutta la classe.
Sauleil,

3

È possibile utilizzare un costrutto come una classe di tratti . In questo modo, avresti una classe helper parametrizzata che sa come convertire una stringa in un valore del suo stesso tipo. Quindi il tuo getter potrebbe apparire così:

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

Ora, devo sottolineare che la mia esperienza con i tipi con parametri è limitata a C ++ e ai suoi modelli, ma immagino che ci sia un modo per fare lo stesso tipo di cose usando C # generics.


Le versioni generiche non esistono in C #.
Shimmy Weitzhandler,

3

Controlla la statica Nullable.GetUnderlyingType. - Se il tipo sottostante è nullo, il parametro template non lo èNullable e possiamo usarlo direttamente - Se il tipo sottostante non è null, utilizzare il tipo sottostante nella conversione.

Sembra funzionare per me:

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

Ispirandosi alla risposta di Bob , queste estensioni supportano anche la conversione di valore null e tutta la conversione primitiva indietro e quarta.

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

Esempi

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

Sto usando la conversione tramite un oggetto. È un po 'più semplice.


grazie devo convertire una T in un'interfaccia e la semplice conversione oggetto T funziona correttamente, facile e veloce grazie
LXG

5
(int) (oggetto) "54"; è una FATALITÀ !, questo non è VB!
Tomer W,

0

Ho usato lobos answer e funziona. Ma ho avuto un problema con la conversione dei doppi a causa delle impostazioni della cultura. Quindi ho aggiunto

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

0

Ancora un'altra variazione. Gestisce nullullabili, nonché situazioni in cui la stringa è nulla e T non è nullable.

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

Puoi farlo in una riga come di seguito:

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

Buona codifica;)


Quando hai condiviso il codice come risposta, prova a spiegarlo.
Yunus Temurlenk,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.