Existe alguma função Parse () genérica que converterá uma string em qualquer tipo usando parse?

93

Eu quero converter uma string em um tipo genérico como intou dateou com longbase no tipo de retorno genérico.

Basicamente, uma função como Parse<T>(String)essa retorna um item do tipo T.

Por exemplo, se um int foi passado, a função deve ser executada int.parseinternamente.

Karim
fonte

Respostas:

134

System.Convert.ChangeType

Conforme seu exemplo, você poderia fazer:

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

Para satisfazer seu requisito de "tipo de retorno genérico", você pode escrever seu próprio método de extensão:

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

Isso permitirá que você faça:

int i = "123".ChangeType<int>();
Ani
fonte
legal, mas o estranho se chama ChangeType, então pensei que essa função faz algum tipo de conversão e não analisa
Karim
7
O MSDN diz que é simplesmente um invólucro que encontra o método de conversão correto no objeto de origem, exigindo que implemente a interface IConvertible.
Ani
Se for necessário implementar IConvertable, você também não deve restringir o T, isto é T ChangeType<T>(this object obj) where T : IConvertable?
Liam
2
@Liam: Não, objdeve ser IConvertible, mas não há como especificar isso em tempo de compilação.
Ani
se eu precisar de algo como TryChangeType que retorna nulo ou falso em caso de falha? Apenas capturando a exceção?
Hopeless
22

Bem, parece que estou muito atrasado para responder a esta discussão. Mas aqui está minha implementação:

Basicamente, criei um método de extensão para a classe Object. Ele lida com todos os tipos, ou seja, anulável, classes e estrutura.

 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;
           }
Pranay Deep
fonte
IMHO esta é a melhor resposta porque também contém o aspecto "anulável"
Ole Albers
há um motivo específico pelo qual você está usando TypeDescriptorpara tipos anuláveis ​​e Convert.ChangeTypenão anuláveis? Todo esse trybloco pode ser reduzido a apenas TypeConverter2 linhas de código e funcionará para ambos, anulável e não anulável.
IMujagic
9

System.Convert.ChangeTypenão converte para nenhum tipo. Pense no seguinte:

  • tipos anuláveis
  • enums
  • Guid etc.

Essas conversões são possíveis com esta implementação de ChangeType .

Alex Siepman
fonte
9

versão mais limpa da resposta de Pranay

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);
    }
}
Eonasdan
fonte
0

Existem algumas convenções no .NET para converter objetos de um tipo em outro.

Mas esses métodos são muito mais lentos do que o normal T.Parse(string), causam encaixotamento e envolvem muitas alocações cada vez que você deseja converter um único valor.

Para ValueString , escolhi encontrar um método de análise estática adequado do tipo usando reflexão, construir uma expressão lambda chamando-o e armazenar em cache o delegado compilado para uso futuro (veja esta resposta para um exemplo).

Ele também retorna para as maneiras que mencionei acima se o tipo não tiver um método de análise adequado (consulte a seção de desempenho no leiame).

var v = new ValueString("15"); // struct
var i = v.As<int>(); // Calls int.Parse.
Şafak Gür
fonte