Czy istnieje ogólna funkcja Parse (), która konwertuje ciąg znaków na dowolny typ przy użyciu analizy?

91

Chcę przekonwertować ciąg na typ ogólny, taki jak intlub datelub longna podstawie ogólnego typu zwracanego.

Zasadniczo funkcja taka jak Parse<T>(String)ta zwraca element typu T.

Na przykład, jeśli przekazano int, funkcja powinna działać int.parsewewnętrznie.

Karim
źródło

Odpowiedzi:

132

System.Convert.ChangeType

Jak na twoim przykładzie, możesz zrobić:

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

Aby spełnić wymóg „ogólnego typu zwracanego”, możesz napisać własną metodę rozszerzenia:

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

Umożliwi to:

int i = "123".ChangeType<int>();
Ani
źródło
fajne, ale dziwna rzecz nazywa się ChangeType, więc pomyślałbym, że ta funkcja wykonuje jakieś rzutowanie, a nie parsuje
Karim
7
MSDN twierdzi, że jest to po prostu opakowanie, które znajduje właściwą metodę konwersji w obiekcie źródłowym, wymagając implementacji interfejsu IConvertible.
Ani,
Jeśli trzeba zaimplementować, IConvertableczy nie należy również ograniczać T, tj. T ChangeType<T>(this object obj) where T : IConvertable?
Liam
2
@Liam: Nie, tak objmusi być IConvertible, ale nie ma sposobu, aby to określić w czasie kompilacji.
Ani
jeśli potrzebuję czegoś takiego jak TryChangeType, który zwraca wartość null lub false w przypadku niepowodzenia? Tylko łapiąc wyjątek?
Beznadziejne
21

Wygląda na to, że jestem już za późno na odpowiedź w tym wątku. Ale oto moja realizacja:

Zasadniczo utworzyłem metodę Extention dla klasy Object. Obsługuje wszystkie typy, tj. Dopuszcza wartość null, klasy i strukturę.

 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
źródło
IMHO to jest lepsza odpowiedź, ponieważ zawiera również aspekt „zerowy”
Ole Albers
czy istnieje konkretny powód, dla którego używasz TypeDescriptordla typów dopuszczających wartość null i Convert.ChangeTypedla typów nie dopuszczających wartości null? Cały tryblok można zredukować tylko do TypeConverter2 wierszy kodu i będzie działał zarówno dla wartości null, jak i non-nullable.
IMujagic
9

System.Convert.ChangeTypenie konwertuje na żaden typ. Pomyśl o następujących kwestiach:

  • typy dopuszczające wartość null
  • wyliczenia
  • Guid itp.

Te konwersje są możliwe dzięki tej implementacji ChangeType .

Alex Siepman
źródło
8

czystsza wersja odpowiedzi Pranaya

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
źródło
0

W .NET istnieje kilka konwencji konwertowania obiektów jednego typu na inny.

Ale te metody są znacznie wolniejsze niż typowe T.Parse(string), powodują boksowanie i wymagają wielu alokacji za każdym razem, gdy chcesz przekonwertować pojedynczą wartość.

W przypadku ciągu ValueString zdecydowałem się znaleźć odpowiednią, statyczną metodę analizy typu przy użyciu odbicia, zbudować wyrażenie lambda wywołujące ją i buforować skompilowanego delegata do wykorzystania w przyszłości (przykład można znaleźć w tej odpowiedzi ).

Jeśli typ nie ma odpowiedniej metody analizy, odwołuje się do sposobów, o których wspomniałem powyżej (zobacz sekcję dotyczącą wydajności w pliku Readme).

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