在我的应用程序中,我有一个小动作日志。在那里,我在我的应用程序中保存了某些方法的最后几次调用,如下所示:
saveLastAction(MethodBase.GetCurrentMethod(), getCurrentStatus(), item, /*loadFresh*/ false);
它允许我导航并刷新我的上一个动作
public void Refresh(bool loadFresh = true)
{
if (!isInitialized) return;
try
{
lastStatus = getCurrentStatus();
var parameters = lastActionsParameters.Pop();
var method = lastActions.Pop();
//Set the load Fresh parameter to True
parameters[method.GetParameters().First(pi => pi.Name == "loadFresh").Position] = loadFresh;
//Invoke the Method again with the adopted parameters
method.Invoke(this, parameters);
}
catch
{
}
}
我工作得很好,直到我改变了一个调用saveLastAction为异步的方法。从那时起MethodBase.GetCurrentMethod()
只返回MoveNext函数,而不是我调用的实际函数。
有没有办法到达被调用函数的实际MethodBase对象,无论是在保存还是调用时都不重要。
祝你好运 lolsharp
答案 0 :(得分:2)
我创建了一个小帮助功能:
private MethodInfo getMethodBase(object caller, [CallerMemberName]string methodName = "")
{
//Binding Flags to include private functions
return caller.GetType().GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public);
}
直接使用CallerMemberNameAttribute并不起作用,因为我还使用了params参数。最后与Peters的做法非常相似。
答案 1 :(得分:0)
你真的需要MethodBase
对象吗?或者仅仅记录足够的细节,人类可以找出它是哪种方法就足够了?
如果是后者,那么它非常简单:请注意,正在执行的方法实际上包含在编译器生成的类中,其中类名本身包含编译器重写以生成该方法的方法的名称类。
因此,在saveLastAction()
方法中,您可能需要记录MethodBase.Name
属性值,首先应检查MethodBase.DeclaringType.Name
值,如果它看起来像<SomeMethodName>d_5
(其中)关闭尖括号后的细节也可能不同),您可以使用尖括号内的文本作为方法名称,而不是MethodBase.Name
属性值。
请注意,只允许编译器使用这些尖括号生成类名,因此您不必担心会出现误报。
作为额外的好处,这将允许您的日志记录代码也可以使用迭代器方法。 :)
如果您需要MethodBase
对象本身,那有点复杂,但会遵循相同的基本策略。获取方法名称,然后在MethodBase.DeclaringType.DeclaringType
类型(即包含编译器生成的类型的类型)中查找该方法。请注意,如果该方法存在多个重载,则识别所使用的特定重载可能会非常棘手或不切实际。
答案 2 :(得分:0)
在C#7 using local functions中,这将变得更容易:
public Task DoAThingAsync()
{
var method = MethodBase.GetCurrentMethod();
LogMethod(method);
return doWork();
// Define inner function to actually do the work
async Task doWork()
{
// Do the work here
}
}
您已经可以使用匿名方法或委托实现此目的,但这使代码非常清晰。