Typowa konwersja typu z ciągu

234

Mam klasę, której chcę użyć do przechowywania „właściwości” innej klasy. Te właściwości mają po prostu nazwę i wartość. Idealnie, chciałbym móc dodawać właściwości pisane na maszynie , tak aby zwracana „wartość” była zawsze zgodna z typem, jaki chcę.

Ten typ powinien zawsze być prymitywny. Ta klasa podklasuje klasę abstrakcyjną, która zasadniczo przechowuje nazwę i wartość jako ciąg znaków. Pomysł polega na tym, że ta podklasa doda pewne bezpieczeństwo typu do klasy bazowej (a także uratuje mnie przy pewnej konwersji).

Stworzyłem klasę, która jest (z grubsza) tym:

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

Pytanie brzmi:

Czy istnieje „ogólny” sposób na konwersję łańcucha znaków z powrotem na prymityw?

Nie mogę znaleźć żadnego ogólnego interfejsu, który łączy konwersję na całym forum (coś takiego jak ITryParsable byłoby idealne!).

Rob Cooper
źródło
Chciałbym zobaczyć przykład twojej konkretnej klasy, nawet zwykły fragment. :)
Jon Limjap,
czy możesz napisać odpowiednie części swojej klasy podstawowej?
JJS,
Zastanawiam się, czy ktokolwiek może uzyskać odpowiedzi tutaj, pracując w .Net Standard 1.2: /
Dan Rayson

Odpowiedzi:

374

Nie jestem pewien, czy poprawnie zrozumiałem twoje intencje, ale zobaczmy, czy to pomaga.

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();}
    }
}
lubos hasko
źródło
Od kilku dni zastanawiam się, jak przekształcić strumień w typowy rodzaj. Dzięki :)
Trap
3
Zgadzam się, chociaż Convert.ChangeTypenie jest to zbyt uniwersalne i rozszerzalne rozwiązanie, ale działa na większość podstawowych typów. jeśli potrzebne jest coś lepszego, nie ma problemu, aby zawinąć tę metodę w coś większego, jak sugeruje Tim, lub użyć innej metody konwersji.
lubos hasko
18
Na pewno dodałbym, gdzie T: IConvertible
MikeT
5
Typ T nie powinien być odwracalny, ale typ podstawy. Wartość powinna.
chapluck
74

Metoda lubos hasko zawodzi w przypadku wartości zerowych. Poniższa metoda będzie działać w przypadku wartości zerowych. Jednak nie wpadłem na to. Znalazłem go za pośrednictwem Google: http://web.archive.org/web/20101214042641/http://dogaoztuzun.com/post/C-Generic-Type-Conversion.aspx Kredyt dla „Tuna Toksoz”

Pierwsze użycie:

TConverter.ChangeType<T>(StringValue);  

Klasa jest poniżej.

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)));
    }
}
Tim Coker
źródło
Dodałbym opcje konwersji rezerwowej dla Enums i innych złożonych struktur, ale dobre połączenie.
Tomer W
2
Dlaczego RegisterTypeConverter? Czy musimy wcześniej zarejestrować konwertery? (niestety link jest martwy, więc nie mogłem go przeczytać)
Cohen
Dla wielu konwersji powinieneś utworzyć tc(na TypeConverter) jeden jedyny raz. TypeConverterjest wolny, ponieważ używa refleksji do wyszukiwania TypeConverterAttribute. Jeśli zainicjujesz pojedyncze TypeConverterpole prywatne , powinieneś być w stanie wielokrotnie korzystać z niego TypeConverterwielokrotnie.
Kevin P. Rice
Działa dobrze, ale jeśli T jest an object, zgłasza wyjątek. Byłem w stanie to obejść, używając `if (typeof (T) .IsPrimitive) {return TConverter.ChangeType <T> (StringValue); } else {object o = (object) StringValue; wrócić do; } `jako zamiennik dla próbki użycia TConverter.ChangeType<T>(StringValue)
Matt
14

Dla wielu typów (liczba całkowita, podwójna, data i godzina itp.) Istnieje statyczna metoda analizy składni. Możesz go wywołać za pomocą odbicia:

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

if (m != null)
{
    return m.Invoke(null, new object[] { base.Value });
}
dbkk
źródło
8
TypeDescriptor.GetConverter(PropertyObject).ConvertFrom(Value)

TypeDescriptorjest klasą posiadającą metodę, GetConvertorktóra akceptuje Typeobiekt, a następnie można wywołać ConvertFrommetodę konwersji valuetego określonego obiektu.

Dinesh Rathee
źródło
Osobiście uważam, że ten interfejs jest lepszy do obsługi konwersji zamiast metody Convert.ChangeType, ponieważ musisz zaimplementować interfejs IConvertible we wszystkich klasach.
Sauleil
3

Możesz użyć konstrukcji takiej jak klasa cech . W ten sposób uzyskałbyś sparametryzowaną klasę pomocnika, która wie, jak przekonwertować ciąg znaków na wartość własnego typu. Wtedy twój getter może wyglądać następująco:

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

Teraz muszę zaznaczyć, że moje doświadczenie ze sparametryzowanymi typami jest ograniczone do C ++ i jego szablonów, ale wyobrażam sobie, że jest jakiś sposób na zrobienie tego samego za pomocą generycznych C #.

Greg Hewgill
źródło
Wersje ogólne nie istnieją w języku C #.
Shimmy Weitzhandler,
3

Sprawdź statyczny Nullable.GetUnderlyingType. - Jeśli typ bazowy ma wartość NULL, parametr szablonu nie jest Nullablei możemy użyć tego typu bezpośrednio - Jeśli typ bazowy nie ma wartości NULL, użyj typu bazowego w konwersji.

Wydaje się dla mnie pracować:

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");
}
Bob C.
źródło
1

Z inspiracji odpowiedzią Boba te rozszerzenia obsługują również konwersję wartości zerowej i wszystkie pierwotne konwersje wstecz i czwarte.

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

Przykłady

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

            int? intValue = null;
            var strResult = intValue.Convert<string>();
Ghominejad
źródło
0
public class TypedProperty<T> : Property
{
    public T TypedValue
    {
        get { return (T)(object)base.Value; }
        set { base.Value = value.ToString();}
    }
}

Korzystam z konwersji za pomocą obiektu. To jest trochę prostsze.

Mastahh
źródło
dzięki Muszę przekonwertować T w interfejsie, a prosta konwersja Obiekt T działa poprawnie, łatwo i szybko dzięki
LXG
5
(int) (object) „54”; jest FATALITY !, to nie jest VB!
Tomer W
0

Użyłem odpowiedzi lobos i to działa. Miałem jednak problem z konwersją podwójnych z powodu ustawień kultury. Więc dodałem

return (T)Convert.ChangeType(base.Value, typeof(T), CultureInfo.InvariantCulture);
anhoppe
źródło
0

Kolejna odmiana. Obsługuje wartości zerowalne, a także sytuacje, w których ciąg jest zerowy, a liter T nie ma wartości zerowej .

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(); }
    }
}
Todd Menier
źródło
0

Możesz to zrobić w jednym wierszu, jak poniżej:

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

Szczęśliwego kodowania;)

Hemendra
źródło
Gdy udostępniasz kod jako odpowiedź, spróbuj go wyjaśnić.
Yunus Temurlenk