2012-11-14 13 views
8

Ho un string e un Type e voglio convertire il valore string convertito in quello Type.Converti da stringa a qualsiasi tipo base

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

Ciò restituisce un object che posso utilizzare in una chiamata valore di insieme di proprietà:

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

Questo funziona per la maggior parte dei tipi di base, ad eccezione 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 fallisce in prima linea con:

System.InvalidCastException: cast non valida dal 'System.String' a 'System.Nullable`1 [[System.Int32, mscorlib, Version = 4.0 .0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089]] '.

Ho difficoltà a rilevare se il tipo è annullabile e modifica il comportamento del metodo StringToType.

Comportamento Sono dopo:

Se stringa è nulla o vuota, restituire NULL, altrimenti convertire secondo tipo non nullable.

Risultato

Come risposta di Kirill, solo con un ChangeType chiamata.

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

È possibile rendere il vostro metodo generico: 'StringToType (valore stringa) oggetto statico pubblico dove T: struct' ... –

+0

@KarelFrajtak Na, a causa del modo in cui è chiamato, vedi il secondo frammento di codice. 'prop.PropertyType' è di riflessione, quindi non è noto fino al runtime. – weston

+0

Il tuo controllo 'if' non è corretto. I tuoi casi speciali non dovrebbero essere per * qualsiasi * tipo generico, dovrebbe essere * solo * per un 'Nullable ' perché sono in scatola in modo diverso. – Servy

risposta

4

Non è possibile utilizzare Convert.ChangeType su tipi nullable perché non è ereditato da IConvertible. Dovresti riscrivere il tuo metodo.

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

provare questo:

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

Buono, manca la logica per gestire stringhe vuote o vuote. – weston

+0

Manca anche una spiegazione del perché questo funziona. – Servy

+0

hai scritto una buona spiegazione Servy [link] (http://stackoverflow.com/a/13381751/1173331) –

0

è necessario utilizzare un metodo di fusione appropriato per ogni tipo che si desidera supportare.

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

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

È impossibile per il compilatore calcolare il tipo in base al contenuto della stringa. Vedere i seguenti collegamenti per ulteriori informazioni sulla conversione da stringhe a tipi di scalari: http://msdn.microsoft.com/en-us/library/bb397679.aspx e http://msdn.microsoft.com/en-us/library/bb384043.aspx.

+0

Certo che sarebbe impossibile, ma non sto chiedendo al compilatore di calcolare il tipo. Ho il tipo di destinazione in 'Type propertyType' – weston

2

Il problema qui è che il valore di ritorno di ChangeType, così come il vostro metodo, è object. Quando si inserisce un qualsiasi tipo annullabile in un object, non inserisce il tipo nullable. Se il valore, in fase di esecuzione, è effettivamente nullo, esso contiene un valore null e, se ha un valore, inserisce il valore sottostante effettivo (anziché la versione nullable).

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

Questo non accadrà nel caso generale con nessun altro tipo; Nullable<T> ha un supporto speciale per il compilatore.Fondamentalmente avrai bisogno del caso speciale Nullable nel tuo codice; Se il metodo viene passato a un tipo Nullable, è necessario prima controllare l'oggetto per null e, se non lo è null, utilizzare invece il tipo sottostante di Nullable.

1

Il codice con l'aiuto del frammento di 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); 
} 

e l'uso (WL scrive solo per consolare). Avevi ragione, il metodo generico non può usare int? come parametro generico.

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

quello che stavo dicendo è che non puoi usarlo in questo modo con reflection, vedi il mio metodo SetBasicPropertyValueFromString per come deve essere usato. – weston

+0

Hai ragione, ma in prova non stai usando il modo in cui descrivi. Un metodo è utile nel codice e l'altro nei test. Non sto dicendo che devi farlo a modo mio, sto solo estendendo la tua idea. –

Problemi correlati