Преобразование общего типа из строки


234

У меня есть класс, который я хочу использовать для хранения «свойств» для другого класса. Эти свойства просто имеют имя и значение. В идеале я хотел бы иметь возможность добавлять типизированные свойства, чтобы возвращаемое «значение» всегда имело тот тип, который я хочу.

Тип всегда должен быть примитивным. Этот класс подклассов абстрактный класс, который в основном хранит имя и значение в виде строки. Идея состоит в том, что этот подкласс добавит некоторую безопасность типов в базовый класс (а также сэкономит мне на некотором преобразовании).

Итак, я создал класс, который (примерно) это:

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

Итак, вопрос в следующем:

Есть ли «общий» способ преобразования строки обратно в примитив?

Я не могу найти какой-либо универсальный интерфейс, который связывает преобразование по всем направлениям (что-то вроде ITryParsable было бы идеально!).


Мне было бы интересно увидеть пример вашего конкретного класса, даже просто фрагмент. :)
Джон Лимджап

Можете ли вы опубликовать соответствующие части вашего базового класса?
JJS

Интересно, кто-нибудь может получить ответы здесь, работая в .Net Standard 1.2: /
Дэн Рэйсон

Ответы:


374

Я не уверен, правильно ли я понял ваши намерения, но давайте посмотрим, поможет ли это.

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

Несколько дней мне было интересно, как десериализовать поток в общий тип. Спасибо :)
Trap

3
Я согласен, хотя Convert.ChangeTypeэто не очень универсальное и расширяемое решение, оно работает для большинства основных типов. если нужно что-то лучшее, нет проблем, чтобы обернуть этот метод во что-то большее, как предложил Тим, или использовать другой метод преобразования.
lubos hasko

18
Я определенно добавил бы, где T: IConvertible
MikeT

5
Тип T не должен быть IConvertible, но тип base.Value должен.
Чаплак

74

Метод Любоша Хаско не подходит для nullables. Метод ниже будет работать для обнуляемых. Я не придумал это, все же. Я нашел его через Google: http://web.archive.org/web/20101214042641/http://dogaoztuzun.com/post/C-Generic-Type-Conversion.aspx Кредит "Тунец Токсоз"

Использование в первую очередь:

TConverter.ChangeType<T>(StringValue);  

Класс ниже.

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

я бы добавил опции конвертации в Fallback для структур Enums и Other Complex, но это хороший вызов.
Томер W

2
Почему RegisterTypeConverter? Нужно ли регистрировать конвертеры заранее? (к сожалению, ссылка мертва, поэтому я не смог ее прочитать)
Коэн

Для нескольких конверсий вы, вероятно, должны создавать tc( TypeConverter) только один раз. TypeConverterмедленный, потому что он использует отражение для поиска TypeConverterAttribute. Если вы инициализируете одно приватное TypeConverterполе, вы сможете использовать его TypeConverterмного раз.
Кевин П. Райс

Работает нормально, но если T является object, выдает исключение. Я смог обойти это, используя `if (typeof (T) .IsPrimitive) {return TConverter.ChangeType <T> (StringValue); } else {object o = (object) StringValue; Вернуться к; } `в качестве замены для примера использования TConverter.ChangeType<T>(StringValue)
Мэтт

14

Для многих типов (целое, двойное, DateTime и т. Д.) Существует статический метод Parse. Вы можете вызвать его, используя отражение:

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это класс, имеющий метод, GetConvertorкоторый принимает Typeобъект, а затем вы можете вызвать ConvertFromметод для преобразования valueуказанного объекта.


Я лично думаю, что этот интерфейс лучше для обработки преобразования вместо метода Convert.ChangeType, так как вам нужно реализовать интерфейс IConvertible во всех ваших классах.
Sauleil

3

Вы могли бы использовать такую ​​конструкцию, как класс черт . Таким образом, у вас будет параметризованный вспомогательный класс, который знает, как преобразовать строку в значение ее собственного типа. Тогда ваш геттер может выглядеть так:

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

Теперь я должен отметить, что мой опыт работы с параметризованными типами ограничен C ++ и его шаблонами, но я думаю, что есть какой-то способ сделать то же самое с использованием обобщений C #.


Универсальные версии не существуют в C #.
Шимми Вайцхандлер

3

Проверьте статический Nullable.GetUnderlyingType. - Если базовый тип является нулевым, тогда параметр шаблона неNullable , и мы можем использовать этот тип напрямую. - Если базовый тип не является NULL, тогда используйте базовый тип в преобразовании.

Кажется, работает на меня:

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

Вдохновленные ответом Боба , эти расширения также поддерживают преобразование нулевого значения и все примитивное преобразование назад и четвертое.

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

Примеры

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

Я использую преобразование через объект. Это немного проще.


спасибо, я должен преобразовать T в интерфейсе, и простой объект преобразования T работает правильно, легко и быстро, спасибо
LXG

5
(INT) (объект) "54"; это СМЕРТЬ !, это не VB!
Томер W

0

Я использовал ответ Лобоса, и он работает. Но у меня была проблема с конвертацией двойников из-за настроек культуры. Итак, я добавил

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

0

Еще один вариант. Обрабатывает Nullables, а также ситуации, когда строка имеет значение NULL и T не имеет значения NULL.

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

Вы можете сделать это в одну строку, как показано ниже:

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

Удачного кодирования;)


Когда вы поделились кодом в качестве ответа, пожалуйста, попробуйте объяснить это.
Юнус Темурленк
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.