de varias fuentes en teh interwebs He obtenida esta función siguiente:Cómo utilizar la reflexión para obtener el método de extensión en el tipo genérico de
public static Nullable<T> TryParseNullable<T>(this Nullable<T> t, string input) where T : struct
{
if (string.IsNullOrEmpty(input))
return default(T);
Nullable<T> result = new Nullable<T>();
try
{
IConvertible convertibleString = (IConvertible)input;
result = new Nullable<T>((T)convertibleString.ToType(typeof(T), CultureInfo.CurrentCulture));
}
catch (InvalidCastException) { }
catch (FormatException) { }
return result;
}
me he hecho en un método de extensión, y funciona muy bien si lo llamo directamente:
int? input = new int?().TryParseNullable("12345");
Mi problema ocurre cuando intento llamarlo usando la reflexión dentro del contexto de otra función genérica. SO está lleno de respuestas que describen cómo obtener MethodInfo de métodos genéricos y métodos estáticos, pero parece que no puedo juntarlos de la manera correcta.
he determinado correctamente que el tipo genérico pasado es en sí mismo un tipo genérico (Nullable<>
), ahora quiero utilizar la reflexión para llamar al método TryParseNullable
extensión en el Nullable<>
:
public static T GetValue<T>(string name, T defaultValue)
{
string result = getSomeStringValue(name);
if (string.IsNullOrEmpty(result)) return defaultValue;
try
{
if (typeof(T).IsGenericType && typeof(T).GetGenericTypeDefinition() == typeof(Nullable<>))
{
MethodInfo methodInfo;
//using the TryParse() of the underlying type works but isn't exactly the way i want to do it
//-------------------------------------------------------------------------------------------
NullableConverter nc = new NullableConverter(typeof(T));
Type t = nc.UnderlyingType;
methodInfo = t.GetMethod("TryParse", BindingFlags.Public | BindingFlags.Static, Type.DefaultBinder, new[] { typeof(string), t.MakeByRefType() }, null);
if (methodInfo != null)
{
var inputParameters = new object[] { result, null };
methodInfo.Invoke(null, inputParameters);
return (T) inputParameters[1];
}
//start of the problem area
//-------------------------
Type ttype = typeof(T);
//this works but is undesirable (due to reference to class containing the static method):
methodInfo = typeof(ParentExtensionsClass).GetMethod("TryParseNullable", BindingFlags.Public | BindingFlags.Static);
if (methodInfo != null)
Console.WriteLine(methodInfo);
//standard way of getting static method, doesn't work (GetMethod() returns null):
methodInfo = ttype.GetMethod("TryParseNullable", BindingFlags.Public | BindingFlags.Static);
if (methodInfo != null)
Console.WriteLine(methodInfo);
//Jon Skeet's advised method, doesn't work in this case (again GetMethod() returns null):
//(see footnote for link to this answer)
methodInfo = ttype.GetMethod("TryParseNullable");
methodInfo = methodInfo.MakeGenericMethod(ttype);
if (methodInfo != null)
Console.WriteLine(methodInfo);
//another random attempt (also doesn't work):
methodInfo = ttype.GetMethod("TryParseNullable", BindingFlags.Public | BindingFlags.Static, Type.DefaultBinder, new[] { typeof(string) }, null);
if (methodInfo != null)
Console.WriteLine(methodInfo);
}
// if we get this far, then we are not handling the type yet
throw new ArgumentException("The type " + defaultValue.GetType() + " is not yet supported by GetValue<T>.", "T");
}
catch (Exception e)
{
[snip]
}
}
Puede alguien poner fuera de mi miseria?
El typeof(T)
devuelve la información de tipo correcta, supongo que tal vez la estoy utilizando de forma incorrecta con la llamada GetMethod()
, o no he especificado los parámetros correctos con la llamada al GetMethod()
.
1. Link to referenced Jon Skeet answer
¿Está seguro de que el método de extensión se considera como parte del typeof (T)? Mi suposición sería que necesitas recuperar el método de la clase estática que implementa el método de extensión, punto. ¿Has intentado simplemente llamar a GetMethods() e inspeccionar lo que se devuelve? – dlev
Gracias @dlev, esa fue la respuesta. Uno de los fundamentos básicos reales de los métodos de extensión y lo había pasado por alto. – slugster
solo una nota sobre su lógica, ¿por qué devuelve 'default (T)' como 'T?' If 'input == null'? Parece que la lógica 'más correcta' sería devolver nulo. –