Conversione in un Nullable da una stringa utilizzando la riflessione
-
23-08-2019 - |
Domanda
Come posso convertire in un Nullable da una stringa utilizzando la riflessione?
Ho il seguente codice per convertire a quasi ogni tipo di valore dato quasi alcun valore. C'è un po 'di codice di cui sopra questa opzione per utilizzare l'IsAssignableFrom, ecc quindi questa è l'ultima risorsa.
MethodInfo parse = t.GetMethod("Parse", new Type[] { typeof(string) });
if (parse != null)
{
object parsed = parse.Invoke(null, new object[] { value.ToString() });
return (T)parsed;
}
else
{
throw new InvalidOperationException("The value you specified is not a valid " + typeof(T).ToString());
}
Il problema arriva quando voglio convertire a un tipo nullable come a lungo?.
Ovviamente, il tempo? classe non ha un metodo di analisi.
Come posso estrarre il metodo parse dal di nullable modello digitare?
EDIT:
Ecco una breve batteria di test che sto cercando di passare:
[Test]
public void ConverterTNullable()
{
Assert.That((int?)1, Is.EqualTo(Converter<int?>.Convert(1)));
Assert.That((int?)2, Is.EqualTo(Converter<int?>.Convert(2.0d)));
Assert.That(3, Is.EqualTo(Converter<long>.Convert(3)));
Assert.That((object)null, Is.EqualTo(Converter<long?>.Convert("")));
Assert.That((object)null, Is.EqualTo(Converter<long?>.Convert(null)));
Assert.That((object)null, Is.EqualTo(Converter<long?>.Convert(DBNull.Value)));
Assert.That((long)1, Is.EqualTo(Converter<long?>.Convert("1")));
Assert.That((long)2, Is.EqualTo(Converter<long?>.Convert(2.0)));
Assert.That((long?)3, Is.EqualTo(Converter<long>.Convert(3)));
}
E l'intera funzione:
/// <summary>
/// Converts any compatible object to an instance of T.
/// </summary>
/// <param name="value">The value to convert.</param>
/// <returns>The converted value.</returns>
public static T Convert(object value)
{
if (value is T)
{
return (T)value;
}
Type t = typeof(T);
if (t == typeof(string))
{
if (value is DBNull || value == null)
{
return (T)(object)null;
}
else
{
return (T)(object)(value.ToString());
}
}
else
{
if (value is DBNull || value == null)
{
return default(T);
}
if (value is string && string.IsNullOrEmpty((string)value))
{
return default(T);
}
try
{
return (T)value;
}
catch (InvalidCastException)
{
}
if (Nullable.GetUnderlyingType(t) != null)
{
t = Nullable.GetUnderlyingType(t);
}
MethodInfo parse = t.GetMethod("Parse", new Type[] { typeof(string) });
if (parse != null)
{
object parsed = parse.Invoke(null, new object[] { value.ToString() });
return (T)parsed;
}
else
{
throw new InvalidOperationException("The value you specified is not a valid " + typeof(T).ToString());
}
}
}
Soluzione 3
Ho aggiunto questo po ':
if (Nullable.GetUnderlyingType(t) != null)
{
t = Nullable.GetUnderlyingType(t);
}
MethodInfo parse = t.GetMethod("Parse", new Type[] { typeof(string) });
Grazie a tutti!
Altri suggerimenti
Io probabilmente utilizzare la TypeConverter
in questo caso, e ; ad esempio sulla strada ... Nullable.GetUnderlyingType()
static void Main()
{
long? val1 = Parse<long?>("123");
long? val2 = Parse<long?>(null);
}
static T Parse<T>(string value)
{
return (T) TypeDescriptor.GetConverter(typeof(T))
.ConvertFrom(value);
}
Questo dovrebbe al lavoro. (Codice è incorporato in un metodo di estensione per semplicità, anche se potrebbe non essere quello che vuoi.)
public static T? ParseToNullable<T>(this string value) where T : struct
{
var parseMethod = typeof(T).GetMethod("Parse", new Type[] { typeof(string) });
if (parseMethod == null)
return new Nullable<T>();
try
{
var value = parseMethod.Invoke(null, new object[] { value.ToString() });
return new Nullable<T>((T)value);
}
catch
{
return new Nullable<T>();
}
}
Ora, se si desidera che il tipo paramter generica si per essere il tipo nullable piuttosto che quello sottostante (io non vedo proprio un vantaggio in questo), è possibile fare uso di:
Nullable.GetUnderlyingType(typeof(T))
come suggerito Marc Gravell, e richiederebbe solo poche modifiche minori al codice.