问题
in my application i have a little action log. In there I save the last few calls of certain methods in my application like this:
saveLastAction(MethodBase.GetCurrentMethod(), getCurrentStatus(), item, /*loadFresh*/ false);
It allows me to navigate and refresh through my last actions
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
{
}
}
I worked perfectly until i changed one of the methods which calls saveLastAction to async. Since then MethodBase.GetCurrentMethod()
only returns the MoveNext function and not the actual function i called.
Is there a way to get to the actual MethodBase Object of the called function, whether at the time of saving or calling doesn't matter.
Best regards lolsharp
回答1:
I created a little help function:
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);
}
Using the CallerMemberNameAttribute directly didn't work because I was also using params parameter. In the end a very similar to Peters approach.
回答2:
Do you really need the MethodBase
object? Or is it sufficient to just log enough detail that a human can figure out which method it was?
If the latter, then it's fairly simple: note that the method that is executing, is actually contained in a compiler-generated class where the class name itself contains the name of the method the compiler rewrote to generate that class.
So in your saveLastAction()
method, where presumably you log the MethodBase.Name
property value, you should first check the MethodBase.DeclaringType.Name
value, and if it looks like <SomeMethodName>d_5
(where the specifics after the closing angle bracket may vary as well), you can use the text within the angle brackets for the method name instead of the MethodBase.Name
property value.
Note that only the compiler is allowed to generate class names with those angle brackets, so you don't have to worry about getting a false positive.
As an added bonus, this will allow your logging code to work with iterator methods too. :)
If you need the MethodBase
object itself, that's a bit more complicated, but would follow the same basic strategy. Get the method name, and then look that method up in the MethodBase.DeclaringType.DeclaringType
type (i.e. the type that contains the compiler-generated type). Note that if there is more than one overload for the method, identifying the specific overload that was used may be tricky or impractical.
回答3:
This is going to a get a whole lot easier in 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
}
}
You can already achieve this with anonymous methods or delegates but this makes the code it very clearn.
来源:https://stackoverflow.com/questions/28022799/methodbase-object-of-async-function