2012-11-14 16 views
8

Mam string i Type, i chcę zwrócić wartość string przekonwertowany na ten Type.Konwertuj z ciąg na dowolny podstawowy typ

public static object StringToType(string value, Type propertyType) 
{ 
    return Convert.ChangeType(value, propertyType, CultureInfo.InvariantCulture); 
} 

ta zwraca object że można używać w nieruchomości wywołania wartości zadanej:

public static void SetBasicPropertyValueFromString(object target, 
                string propName, 
                string value) 
{ 
    PropertyInfo prop = target.GetType().GetProperty(propName); 
    object converted = StringToType(value, prop.PropertyType); 
    prop.SetValue(target, converted, null); 
} 

Działa to dla większości podstawowych typów, z wyjątkiem nullables.

[TestMethod] 
public void IntTest() 
{ //working 
    Assert.AreEqual(1, ValueHelper.StringToType("1", typeof (int))); 
    Assert.AreEqual(123, ValueHelper.StringToType("123", typeof (int))); 
} 

[TestMethod] 
public void NullableIntTest() 
{ //not working 
    Assert.AreEqual(1, ValueHelper.StringToType("1", typeof (int?))); 
    Assert.AreEqual(123, ValueHelper.StringToType("123", typeof (int?))); 
    Assert.AreEqual(null, ValueHelper.StringToType(null, typeof (int?))); 
} 

NullableIntTest nie na pierwszej linii z:

System.InvalidCastException: Nieprawidłowy odlana z 'System.String' do „System.Nullable`1 [[System.Int32, mscorlib, Version = 4,0 .0,0, Culture = neutral, PublicKeyToken = b77a5c561934e089]] '.

Mam trudności z określeniem, czy typ jest zerowy i zmienia zachowanie metody StringToType.

Zachowanie Jestem po:

Jeśli ciąg jest zerowy lub pusty, powrót null, jeszcze konwertować jak na non wartości pustych typu.

Wynik

jak odpowiedź Cyryla, tylko z jednym ChangeType wezwanie.

public static object StringToType(string value, Type propertyType) 
{ 
    var underlyingType = Nullable.GetUnderlyingType(propertyType); 
    if (underlyingType != null) 
    { 
     //an underlying nullable type, so the type is nullable 
     //apply logic for null or empty test 
     if (String.IsNullOrEmpty(value)) return null; 
    } 
    return Convert.ChangeType(value, 
           underlyingType ?? propertyType, 
           CultureInfo.InvariantCulture); 
} 
+0

Można uczynić metoda rodzajowa: 'public static obiekt StringToType (wartość string) gdzie T: struct' ... –

+0

@KarelFrajtak Na, ze względu na sposób to się nazywa, patrz kod drugiego fragmentu. 'prop.PropertyType' pochodzi z odbicia, więc nie jest znane aż do czasu wykonania. – weston

+0

Twoja próba "jeśli" nie jest właściwa. Twoje specjalne przypadki nie powinny być dla * dowolnego * rodzaju ogólnego, powinno to być * tylko * dla 'Nullable ' ponieważ są one oznaczone inaczej. – Servy

Odpowiedz

4

Nie można używać Convert.ChangeType w typach zerowalnych, ponieważ nie jest on dziedziczony z IConvertible. Powinieneś przepisać swoją metodę.

public static object StringToType(string value, Type propertyType) 
{ 
    var underlyingType = Nullable.GetUnderlyingType(propertyType); 
    if(underlyingType == null) 
      return Convert.ChangeType(value, propertyType, CultureInfo.InvariantCulture); 
    return String.IsNullOrEmpty(value) 
      ? null 
      : Convert.ChangeType(value, underlyingType, CultureInfo.InvariantCulture); 

}

2

spróbuj tego:

prop.IsGenericType && Nullable.GetUnderlyingType(prop) == value.GetType() 
3
public static object StringToType(string value, Type propertyType) 
{ 
    var underlyingType = Nullable.GetUnderlyingType(propertyType); 
    return underlyingType == null ? Convert.ChangeType(value, propertyType, CultureInfo.InvariantCulture) : Convert.ChangeType(value, underlyingType, CultureInfo.InvariantCulture); 
} 
+0

Dobra, tylko brakująca logika do obsługi pustych lub pustych ciągów. – weston

+0

Brakuje również wyjaśnienia, dlaczego to działa. – Servy

+0

napisał dobre wyjaśnienie Servy [link] (http://stackoverflow.com/a/13381751/1173331) –

0

należy użyć odpowiedniej metody rzucania dla każdego rodzaju chcesz wesprzeć.

int parsedInt; 
int.TryParse("1", out parsedInt); 

double parsedDouble; 
double.TryParse("0.0d", out parsedDouble); 

Kompilator nie może ustalić typu w zależności od zawartości napisu. Zobacz następujące łącza, aby uzyskać więcej informacji na temat konwersji z typów ciągów na skalarne: http://msdn.microsoft.com/en-us/library/bb397679.aspx i http://msdn.microsoft.com/en-us/library/bb384043.aspx.

+0

Oczywiście, że byłoby to niemożliwe, ale nie pytam kompilatora, aby opracować typ. Mam typ docelowy w 'Type propertyType' – weston

2

Problem polega na tym, że wartość zwracana ChangeType, jak również metoda jest object. Po umieszczeniu dowolnego typu z pustymi literami na object nie powoduje to umieszczenia typu nullable. Jeśli wartość w środowisku wykonawczym jest rzeczywiście pusta, oznacza to, że ma ona wartość null, a jeśli ma wartość, wyświetla rzeczywistą wartość bazową (zamiast wersji zerowej).

int? i = 5; 
object o = i; 
Type t = o.GetType();//will be `int`, not `Nullable<int>` 

Nie stanie się to w ogólnym przypadku z żadnym innym typem; Nullable<T> ma specjalne wsparcie dla kompilatora, aby to zrobić.Zasadniczo potrzebujesz również specjalnego kodu w swoim kodzie: Nullable; Jeśli twoja metoda została przekazana jako typ Nullable, musisz najpierw sprawdzić obiekt pod kątem null, a jeśli nie, null, użyj zamiast tego bazowego typu Nullable.

1

Kod z pomocą urywek Kirill Bestemyanov”:

public static object StringToType<T>(string value) 
{ 
    return StringToType(value, typeof(T)); 
} 

public static object StringToType(string value, Type propertyType) 
{ 
    var underlyingType = Nullable.GetUnderlyingType(propertyType); 
    if(underlyingType == null) 
    return Convert.ChangeType(value, propertyType, CultureInfo.InvariantCulture); 
    return String.IsNullOrEmpty(value) 
    ? null 
    : Convert.ChangeType(value, underlyingType, CultureInfo.InvariantCulture); 
} 

i użytkowania (WL właśnie pisze do konsoli). Miałeś rację, ogólna metoda nie może użyć int? jako parametru ogólnego.

WL(StringToType("1", typeof (int?))); // -> 1 
WL(StringToType<int>("1"));   // -> 1 
WL(StringToType<int?>("1"));   // error, not compilable 
WL(StringToType<Nullable<int>>("1")); // -> 1 
+0

co powiedziałem jest, że nie można używać go tak z odbiciem, zobacz moją metodę SetBasicPropertyValueFromString, jak należy go używać. – weston

+0

Masz rację, ale w teście nie używasz sposobu, w jaki opisujesz. Jedna metoda jest przydatna w kodzie, a druga w testach. Nie mówię, że musisz to robić po swojemu, przedłużam twój pomysł. –