Recuperando el nombre del método invocado ejecutado en un Func
-
22-07-2019 - |
Pregunta
Me gustaría obtener el nombre del método que se delega como Func.
Func<MyObject, object> func = x => x.DoSomeMethod();
string name = ExtractMethodName(func); // should equal "DoSomeMethod"
¿Cómo puedo lograr esto?
- Para alardear de derechos -
Haga que ExtractMethodName
también funcione con una invocación de propiedad, haciendo que devuelva el nombre de la propiedad en esa instancia.
ej.
Func<MyObject, object> func = x => x.Property;
string name = ExtractMethodName(func); // should equal "Property"
Solución
¡Mira mamá! ¡Sin árboles de expresión!
Aquí hay una versión rápida, sucia y específica de la implementación que toma el token de metadatos del flujo IL del lambda subyacente y lo resuelve.
private static string ExtractMethodName(Func<MyObject, object> func)
{
var il = func.Method.GetMethodBody().GetILAsByteArray();
// first byte is ldarg.0
// second byte is callvirt
// next four bytes are the MethodDef token
var mdToken = (il[5] << 24) | (il[4] << 16) | (il[3] << 8) | il[2];
var innerMethod = func.Method.Module.ResolveMethod(mdToken);
// Check to see if this is a property getter and grab property if it is...
if (innerMethod.IsSpecialName && innerMethod.Name.StartsWith("get_"))
{
var prop = (from p in innerMethod.DeclaringType.GetProperties()
where p.GetGetMethod() == innerMethod
select p).FirstOrDefault();
if (prop != null)
return prop.Name;
}
return innerMethod.Name;
}
Otros consejos
No creo que esto sea posible en el caso general. ¿Qué pasaría si tuvieras:
Func<MyObject, object> func = x => x.DoSomeMethod(x.DoSomeOtherMethod());
¿Qué esperarías?
Dicho esto, puedes usar la reflexión para abrir el objeto Func y ver qué hace dentro, pero solo podrás resolverlo en ciertos casos.
Mira mi respuesta de pirateo aquí:
¿Por qué no hay un `fieldof Operador `o` methodof` en C #?
En el pasado lo hice de otra manera que usaba Func
en lugar de Expression<Func<...>>
, pero estaba mucho menos satisfecho con el resultado. El MemberExpression
utilizado para detectar el campo en mi método fieldof
devolverá un PropertyInfo
cuando se utiliza una propiedad.
Editar # 1: Esto funciona para un subconjunto del problema:
Func<object> func = x.DoSomething;
string name = func.Method.Name;
Edición n. ° 2: Quien me haya marcado debe tomarse un segundo para darse cuenta de lo que está sucediendo aquí. Los árboles de expresión pueden usarse implícitamente con expresiones lambda y son la forma más rápida y confiable de obtener la información solicitada específica aquí.