Есть ли какая-нибудь универсальная функция Parse (), которая преобразует строку в любой тип с помощью синтаксического анализа?

91

Я хочу преобразовать строку в универсальный тип, например intили dateили longна основе универсального возвращаемого типа.

По сути, такая функция Parse<T>(String)возвращает элемент типа T.

Например, если было передано int, функция должна работать int.parseвнутри.

Карим
источник

Ответы:

132

System.Convert.ChangeType

В соответствии с вашим примером вы можете:

int i = (int)Convert.ChangeType("123", typeof(int));
DateTime dt = (DateTime)Convert.ChangeType("2009/12/12", typeof(DateTime));

Чтобы удовлетворить ваше требование «универсального возвращаемого типа», вы можете написать свой собственный метод расширения:

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

Это позволит вам:

int i = "123".ChangeType<int>();
Ани
источник
круто, но странно то, что она называется ChangeType, поэтому я подумал, что эта функция выполняет какое-то приведение, а не синтаксический анализ
Карим
7
MSDN утверждает, что это просто оболочка, которая находит правильный метод преобразования в исходном объекте, требуя, чтобы она реализовывала интерфейс IConvertible.
Ани
Если это необходимо реализовать, IConvertableне следует ли вам также ограничивать T, т.е. T ChangeType<T>(this object obj) where T : IConvertable?
Лиам
2
@Liam: Нет, это objдолжно быть так IConvertible, но нет возможности указать это во время компиляции.
Ani
если мне нужно что-то вроде TryChangeType, которое в случае неудачи возвращает null или false? Только поймав исключение?
Hopeless
21

Похоже, я слишком поздно отвечать в этой теме. Но вот моя реализация:

По сути, я создал метод расширения для класса Object. Он обрабатывает все типы, то есть обнуляемые, классы и структуры.

 public static T ConvertTo<T>(this object value)
           {
               T returnValue;

               if (value is T variable)
                   returnValue = variable;
               else
                   try
                   {
                       //Handling Nullable types i.e, int?, double?, bool? .. etc
                       if (Nullable.GetUnderlyingType(typeof(T)) != null)
                       {
                           TypeConverter conv = TypeDescriptor.GetConverter(typeof(T));
                           returnValue = (T) conv.ConvertFrom(value);
                       }
                       else
                       {
                           returnValue = (T) Convert.ChangeType(value, typeof(T));
                       }
                   }
                   catch (Exception)
                   {
                       returnValue = default(T);
                   }

               return returnValue;
           }
Праная глубокая
источник
ИМХО, это лучший ответ, потому что он также содержит аспект, допускающий значение NULL,
Оле Альберс
есть ли конкретная причина, по которой вы используете TypeDescriptorтипы, допускающие значение NULL, и типы, Convert.ChangeTypeне допускающие значения NULL? Весь этот tryблок можно сократить только до TypeConverter2 строк кода, и он будет работать как для обнуляемых, так и для непустых.
IMujagic
9

System.Convert.ChangeTypeне преобразуется ни в один тип. Подумайте о следующем:

  • типы, допускающие значение NULL
  • перечисляет
  • Гид и др.

Эти преобразования возможны с этой реализацией ChangeType .

Алекс Сипман
источник
8

более чистая версия ответа Праная

public static T ConvertTo<T>(this object value)
{
    if (value is T variable) return variable;

    try
    {
        //Handling Nullable types i.e, int?, double?, bool? .. etc
        if (Nullable.GetUnderlyingType(typeof(T)) != null)
        {
            return (T)TypeDescriptor.GetConverter(typeof(T)).ConvertFrom(value);
        }

        return (T)Convert.ChangeType(value, typeof(T));
    }
    catch (Exception)
    {
        return default(T);
    }
}
Эонасдан
источник
0

В .NET существует несколько соглашений для преобразования объектов одного типа в другой.

Но эти методы намного медленнее, чем ваши обычные T.Parse(string), вызывают упаковку и требуют большого количества выделений каждый раз, когда вы хотите преобразовать одно значение.

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

Он также использует способы, упомянутые выше, если у типа нет подходящего метода синтаксического анализа (см. Раздел о производительности в файле readme).

var v = new ValueString("15"); // struct
var i = v.As<int>(); // Calls int.Parse.
Шафак Гюр
источник