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.

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

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

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


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

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.
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.