查找 Func 委托的调用方法的名称
Find the name of the invoked method of a Func delegate
我有一个简单的调用程序,为了能够使用缓存库,我需要知道作为 Func
委托参数的对象的调用方法的名称。
class Program
{
static void Main(string[] args)
{
var proxy = new Proxy();
Invoker.invoke(proxy, p => p.formatSomething("Dumb test"));
}
}
public class Proxy
{
public string formatSomething(string input){
return String.Format("-===={0}====-", input);
}
}
public static class Invoker
{
public static void invoke(Proxy proxy, Func<Proxy,string> online){
//Some caching logic that require the name of the method
//invoked on the proxy (in this specific case "formatSomething")
var methodName = ??;
if (IsCached(proxyName, methodName)){
output = GetFromCache(proxyName, methodName);
}else{
output = online(proxy);
}
}
}
这些是一些可能的(不好的)解决方案:
方案一:添加一个字符串参数传递方法名(容易出错)
public static class Invoker
{
public static void invoke(Proxy proxy, Func<Proxy,string> online, string methodName){
if (IsCached(proxyName, methodName)){
output = GetFromCache(proxyName, methodName);
}else{
output = online(proxy);
}
}
}
解决方案 2: 使用 Expression
可能会出现性能问题。
public static class Invoker
{
public static void invoke(Proxy proxy, Expression<Func<Proxy,string>> online){
var methodName = ((MethodCallExpression)online.Body).Method.Name;
if (IsCached(proxyName, methodName)){
output = GetFromCache(proxyName, methodName);
}else{
output = online.Compile()(proxy);
}
}
}
解决方案 3: 使用 Expression
作为另一个参数(容易出错)。
public static class Invoker
{
public static void invoke(Proxy proxy,Func<Proxy,string> online, Expression<Func<Proxy,string>> online2){
var methodName = ((MethodCallExpression)online2.Body).Method.Name;
if (IsCached(proxyName, methodName)){
output = GetFromCache(proxyName, methodName);
}else{
output = online(proxy);
}
}
}
您是否知道任何其他更好的方法来检查和获取 methodName
Invoker 需要的东西?
注意:
我没有搜索在线函数结果的缓存机制,因为我已经有了它。
唯一的问题是此缓存需要在 Func
委托中调用代理 methodName
。
检查以下代码。如果你想得到方法 FULL_NAME 然后在第一行写下面 #define FULL_NAME
public class Cache
{
private const uint DefaultCacheSize = 100;
private readonly Dictionary<string, object> _cache = new Dictionary<string, object>();
private readonly object _cacheLocker = new object();
private readonly uint _cacheSize;
public Cache(uint cacheSize = DefaultCacheSize)
{
_cacheSize = cacheSize;
}
public uint CacheSize
{
get { return _cacheSize; }
}
public TValue Resolve<TObj, TValue>(TObj item, Func<TObj, TValue> func, [CallerMemberName] string key = "")
{
#if FULL_NAME
var stackTrace = new StackTrace();
var method = stackTrace.GetFrame(1).GetMethod();
key = string.Format("{0}_{1}",
method.DeclaringType == null ? string.Empty : method.DeclaringType.FullName,
method.Name);
#endif
return CacheResolver(item, func, key);
}
private TValue CacheResolver<TObj, TValue>(TObj item, Func<TObj, TValue> func, string key)
{
object res;
if (_cache.TryGetValue(key, out res) && res is TValue)
{
return (TValue) res;
}
TValue result = func(item);
lock (_cacheLocker)
{
_cache[key] = result;
if (_cache.Keys.Count > DefaultCacheSize)
{
_cache.Remove(_cache.Keys.First());
}
}
return result;
}
}
以及用法(来自 Form 对象):
private void CacheTest()
{
var cache = new Cache();
var text = cache.Resolve<Form, string>(this, f => f.Text);
}
希望对你有所帮助
EDIT 我使用表达式进行了测试,没有出现性能问题,第一次大约需要 25 毫秒。您可以将其适配为 Cache
class 以提取参数 Expression<Func<T, T1>>
.
的方法调用表达式
private string GetExpressionMethodCallName<T, T1>(Expression<Func<T, T1>> exp)
{
var mce = exp.Body as MethodCallExpression;
if (mce == null)
throw new InvalidOperationException("invalid expression");
return mce.Method.Name;
}
你需要一个表达式来解析方法的调用名称,但是你可以引入某种二级缓存:一个用于实际的方法调用(不会过期),一个用于方法的调用结果(它可能会过期)。
我认为,您的第二个解决方案方向正确;只编译表达式一次。
public static class Invoker {
public static void Invoke(Proxy proxy, Expression<Func<Proxy,string>> online) {
var methodName = ((MethodCallExpression)online.Body).Method.Name;
if (IsCached(proxyName, methodName)) {
output = GetFromCache(proxyName, methodName);
} else {
if (IsFuncCached(methodName)) {
func = GetFuncFromCache(methodName);
} else {
func = online.Compile();
// add func to "func cache"...
}
output = func(proxy);
}
}
}
我尝试将您的代码改编为示例,希望它有意义。
我最近实施了一个检查 CLR 方法的 IL 指令的解决方案。
你可以这样使用它:
using System;
using System.Linq;
using Reflection.IL;
namespace Whosebug
{
class Program
{
static void Main(string[] args)
{
var proxy = new Proxy();
Invoker.invoke(proxy, p => p.formatSomething("Dumb test"));
}
}
public class Proxy
{
public string formatSomething(string input)
{
return String.Format("-===={0}====-", input);
}
}
public static class Invoker
{
public static void invoke(Proxy proxy, Func<Proxy, string> online)
{
//Some caching logic that require the name of the method
//invoked on the proxy (in this specific case "formatSomething")
var methodName = online.GetCalledMethods().First().Name;
Console.WriteLine(methodName);
}
}
}
请注意,代码未经过全面测试或记录,但我认为它应该可以满足您的需求。这是:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
namespace Reflection.IL
{
public struct ILInstruction
{
public OpCode Code { get; private set; }
public object Operand { get; private set; }
internal ILInstruction(OpCode code, object operand)
: this()
{
this.Code = code;
this.Operand = operand;
}
public int Size
{
get { return this.Code.Size + GetOperandSize(this.Code.OperandType); }
}
public override string ToString()
{
return this.Operand == null ? this.Code.ToString() : string.Format(CultureInfo.InvariantCulture, "{0} {1}", this.Code, this.Operand);
}
private static int GetOperandSize(OperandType operandType)
{
switch (operandType)
{
case OperandType.InlineBrTarget:
case OperandType.InlineField:
case OperandType.InlineI:
case OperandType.InlineMethod:
case OperandType.InlineSig:
case OperandType.InlineString:
case OperandType.InlineSwitch:
case OperandType.InlineTok:
case OperandType.InlineType:
return sizeof(int);
case OperandType.InlineI8:
return sizeof(long);
case OperandType.InlineNone:
return 0;
case OperandType.InlineR:
return sizeof(double);
case OperandType.InlineVar:
return sizeof(short);
case OperandType.ShortInlineBrTarget:
case OperandType.ShortInlineI:
case OperandType.ShortInlineVar:
return sizeof(byte);
case OperandType.ShortInlineR:
return sizeof(float);
default:
throw new InvalidOperationException();
}
}
}
public sealed class MethodBodyIL : IEnumerable<ILInstruction>
{
private readonly MethodBase method;
public MethodBodyIL(MethodBase method)
{
if (method == null)
throw new ArgumentNullException("method");
this.method = method;
}
public Enumerator GetEnumerator()
{
var body = this.method.GetMethodBody();
return new Enumerator(this.method.Module, this.method.DeclaringType.GetGenericArguments(), this.method.GetGenericArguments(), body.GetILAsByteArray(), body.LocalVariables);
}
IEnumerator<ILInstruction> IEnumerable<ILInstruction>.GetEnumerator()
{
return this.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
public struct Enumerator : IEnumerator<ILInstruction>
{
private static readonly IDictionary<short, OpCode> codes = typeof(OpCodes).FindMembers(MemberTypes.Field, BindingFlags.Public | BindingFlags.Static, (m, criteria) => ((FieldInfo)m).FieldType == typeof(OpCode), null).Cast<FieldInfo>().Select(f => (OpCode)f.GetValue(null)).ToDictionary(c => c.Value);
private readonly Module module;
private readonly Type[] genericTypeArguments, genericMethodArguments;
private readonly byte[] il;
private readonly IList<LocalVariableInfo> localVariables;
private int offset;
private ILInstruction current;
internal Enumerator(Module module, Type[] genericTypeArguments, Type[] genericMethodArguments, byte[] il, IList<LocalVariableInfo> localVariables)
{
this.module = module;
this.genericTypeArguments = genericTypeArguments;
this.genericMethodArguments = genericMethodArguments;
this.il = il;
this.localVariables = localVariables;
this.offset = 0;
this.current = default(ILInstruction);
}
public ILInstruction Current
{
get { return this.current; }
}
public bool MoveNext()
{
if (this.offset < this.il.Length)
{
this.current = this.ReadInstruction();
return true;
}
else
{
this.current = default(ILInstruction);
return false;
}
}
public void Reset()
{
this.offset = 0;
this.current = default(ILInstruction);
}
public void Dispose()
{
this.offset = this.il.Length;
this.current = default(ILInstruction);
}
private ILInstruction ReadInstruction()
{
var code = this.ReadCode();
return new ILInstruction(code, this.ReadOperand(code.OperandType));
}
private OpCode ReadCode()
{
var code = codes[this.ReadByte()];
if (code.OpCodeType == OpCodeType.Prefix)
code = codes[(short)(code.Value << 8 | this.ReadByte())];
return code;
}
private object ReadOperand(OperandType operandType)
{
switch (operandType)
{
case OperandType.InlineBrTarget:
case OperandType.InlineI:
case OperandType.InlineSwitch:
return this.ReadInt32();
case OperandType.InlineField:
case OperandType.InlineMethod:
case OperandType.InlineTok:
case OperandType.InlineType:
return this.ReadMember();
case OperandType.InlineI8:
return this.ReadInt64();
case OperandType.InlineNone:
return null;
case OperandType.InlineR:
return this.ReadDouble();
case OperandType.InlineSig:
return this.ReadSignature();
case OperandType.InlineString:
return this.ReadString();
case OperandType.InlineVar:
return this.ReadLocalVariable();
case OperandType.ShortInlineBrTarget:
case OperandType.ShortInlineI:
return this.ReadByte();
case OperandType.ShortInlineR:
return this.ReadSingle();
case OperandType.ShortInlineVar:
return this.ReadLocalVariableShort();
default:
throw new InvalidOperationException();
}
}
private byte ReadByte()
{
var value = this.il[this.offset];
++this.offset;
return value;
}
private short ReadInt16()
{
var value = BitConverter.ToInt16(this.il, this.offset);
this.offset += sizeof(short);
return value;
}
private int ReadInt32()
{
var value = BitConverter.ToInt32(this.il, this.offset);
this.offset += sizeof(int);
return value;
}
private long ReadInt64()
{
var value = BitConverter.ToInt64(this.il, this.offset);
this.offset += sizeof(long);
return value;
}
private float ReadSingle()
{
var value = BitConverter.ToSingle(this.il, this.offset);
this.offset += sizeof(float);
return value;
}
private double ReadDouble()
{
var value = BitConverter.ToDouble(this.il, this.offset);
this.offset += sizeof(double);
return value;
}
private MemberInfo ReadMember()
{
return this.module.ResolveMember(this.ReadInt32(), this.genericTypeArguments, this.genericMethodArguments);
}
private byte[] ReadSignature()
{
return this.module.ResolveSignature(this.ReadInt32());
}
private string ReadString()
{
return this.module.ResolveString(this.ReadInt32());
}
private LocalVariableInfo ReadLocalVariable()
{
return this.localVariables[this.ReadInt16()];
}
private LocalVariableInfo ReadLocalVariableShort()
{
return this.localVariables[this.ReadByte()];
}
object IEnumerator.Current
{
get { return this.Current; }
}
}
}
public static class ILHelper
{
public static MethodBodyIL GetIL(this MethodBase method)
{
return new MethodBodyIL(method);
}
public static IEnumerable<MethodBase> GetCalledMethods(this Delegate methodPtr)
{
if (methodPtr == null)
throw new ArgumentNullException("methodPtr");
foreach (var instruction in methodPtr.Method.GetIL())
if (IsMethodCall(instruction.Code))
yield return (MethodBase)instruction.Operand;
}
private static bool IsMethodCall(OpCode code)
{
return code == OpCodes.Call || code == OpCodes.Calli || code == OpCodes.Callvirt;
}
}
}
您可以使用method.Name获取调用方法名称。
public static class Invoker
{
public static void invoke(Proxy proxy, Func<Proxy, string> online)
{
//Some caching logic that require the name of the method
//invoked on the proxy (in this specific case "formatSomething")
var methodName = online.Method.Name;
}
}
https://msdn.microsoft.com/en-us/library/system.multicastdelegate%28v=vs.110%29.aspx
我有一个简单的调用程序,为了能够使用缓存库,我需要知道作为 Func
委托参数的对象的调用方法的名称。
class Program
{
static void Main(string[] args)
{
var proxy = new Proxy();
Invoker.invoke(proxy, p => p.formatSomething("Dumb test"));
}
}
public class Proxy
{
public string formatSomething(string input){
return String.Format("-===={0}====-", input);
}
}
public static class Invoker
{
public static void invoke(Proxy proxy, Func<Proxy,string> online){
//Some caching logic that require the name of the method
//invoked on the proxy (in this specific case "formatSomething")
var methodName = ??;
if (IsCached(proxyName, methodName)){
output = GetFromCache(proxyName, methodName);
}else{
output = online(proxy);
}
}
}
这些是一些可能的(不好的)解决方案:
方案一:添加一个字符串参数传递方法名(容易出错)
public static class Invoker
{
public static void invoke(Proxy proxy, Func<Proxy,string> online, string methodName){
if (IsCached(proxyName, methodName)){
output = GetFromCache(proxyName, methodName);
}else{
output = online(proxy);
}
}
}
解决方案 2: 使用 Expression
可能会出现性能问题。
public static class Invoker
{
public static void invoke(Proxy proxy, Expression<Func<Proxy,string>> online){
var methodName = ((MethodCallExpression)online.Body).Method.Name;
if (IsCached(proxyName, methodName)){
output = GetFromCache(proxyName, methodName);
}else{
output = online.Compile()(proxy);
}
}
}
解决方案 3: 使用 Expression
作为另一个参数(容易出错)。
public static class Invoker
{
public static void invoke(Proxy proxy,Func<Proxy,string> online, Expression<Func<Proxy,string>> online2){
var methodName = ((MethodCallExpression)online2.Body).Method.Name;
if (IsCached(proxyName, methodName)){
output = GetFromCache(proxyName, methodName);
}else{
output = online(proxy);
}
}
}
您是否知道任何其他更好的方法来检查和获取 methodName
Invoker 需要的东西?
注意:
我没有搜索在线函数结果的缓存机制,因为我已经有了它。
唯一的问题是此缓存需要在 Func
委托中调用代理 methodName
。
检查以下代码。如果你想得到方法 FULL_NAME 然后在第一行写下面 #define FULL_NAME
public class Cache
{
private const uint DefaultCacheSize = 100;
private readonly Dictionary<string, object> _cache = new Dictionary<string, object>();
private readonly object _cacheLocker = new object();
private readonly uint _cacheSize;
public Cache(uint cacheSize = DefaultCacheSize)
{
_cacheSize = cacheSize;
}
public uint CacheSize
{
get { return _cacheSize; }
}
public TValue Resolve<TObj, TValue>(TObj item, Func<TObj, TValue> func, [CallerMemberName] string key = "")
{
#if FULL_NAME
var stackTrace = new StackTrace();
var method = stackTrace.GetFrame(1).GetMethod();
key = string.Format("{0}_{1}",
method.DeclaringType == null ? string.Empty : method.DeclaringType.FullName,
method.Name);
#endif
return CacheResolver(item, func, key);
}
private TValue CacheResolver<TObj, TValue>(TObj item, Func<TObj, TValue> func, string key)
{
object res;
if (_cache.TryGetValue(key, out res) && res is TValue)
{
return (TValue) res;
}
TValue result = func(item);
lock (_cacheLocker)
{
_cache[key] = result;
if (_cache.Keys.Count > DefaultCacheSize)
{
_cache.Remove(_cache.Keys.First());
}
}
return result;
}
}
以及用法(来自 Form 对象):
private void CacheTest()
{
var cache = new Cache();
var text = cache.Resolve<Form, string>(this, f => f.Text);
}
希望对你有所帮助
EDIT 我使用表达式进行了测试,没有出现性能问题,第一次大约需要 25 毫秒。您可以将其适配为 Cache
class 以提取参数 Expression<Func<T, T1>>
.
private string GetExpressionMethodCallName<T, T1>(Expression<Func<T, T1>> exp)
{
var mce = exp.Body as MethodCallExpression;
if (mce == null)
throw new InvalidOperationException("invalid expression");
return mce.Method.Name;
}
你需要一个表达式来解析方法的调用名称,但是你可以引入某种二级缓存:一个用于实际的方法调用(不会过期),一个用于方法的调用结果(它可能会过期)。
我认为,您的第二个解决方案方向正确;只编译表达式一次。
public static class Invoker {
public static void Invoke(Proxy proxy, Expression<Func<Proxy,string>> online) {
var methodName = ((MethodCallExpression)online.Body).Method.Name;
if (IsCached(proxyName, methodName)) {
output = GetFromCache(proxyName, methodName);
} else {
if (IsFuncCached(methodName)) {
func = GetFuncFromCache(methodName);
} else {
func = online.Compile();
// add func to "func cache"...
}
output = func(proxy);
}
}
}
我尝试将您的代码改编为示例,希望它有意义。
我最近实施了一个检查 CLR 方法的 IL 指令的解决方案。
你可以这样使用它:
using System;
using System.Linq;
using Reflection.IL;
namespace Whosebug
{
class Program
{
static void Main(string[] args)
{
var proxy = new Proxy();
Invoker.invoke(proxy, p => p.formatSomething("Dumb test"));
}
}
public class Proxy
{
public string formatSomething(string input)
{
return String.Format("-===={0}====-", input);
}
}
public static class Invoker
{
public static void invoke(Proxy proxy, Func<Proxy, string> online)
{
//Some caching logic that require the name of the method
//invoked on the proxy (in this specific case "formatSomething")
var methodName = online.GetCalledMethods().First().Name;
Console.WriteLine(methodName);
}
}
}
请注意,代码未经过全面测试或记录,但我认为它应该可以满足您的需求。这是:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
namespace Reflection.IL
{
public struct ILInstruction
{
public OpCode Code { get; private set; }
public object Operand { get; private set; }
internal ILInstruction(OpCode code, object operand)
: this()
{
this.Code = code;
this.Operand = operand;
}
public int Size
{
get { return this.Code.Size + GetOperandSize(this.Code.OperandType); }
}
public override string ToString()
{
return this.Operand == null ? this.Code.ToString() : string.Format(CultureInfo.InvariantCulture, "{0} {1}", this.Code, this.Operand);
}
private static int GetOperandSize(OperandType operandType)
{
switch (operandType)
{
case OperandType.InlineBrTarget:
case OperandType.InlineField:
case OperandType.InlineI:
case OperandType.InlineMethod:
case OperandType.InlineSig:
case OperandType.InlineString:
case OperandType.InlineSwitch:
case OperandType.InlineTok:
case OperandType.InlineType:
return sizeof(int);
case OperandType.InlineI8:
return sizeof(long);
case OperandType.InlineNone:
return 0;
case OperandType.InlineR:
return sizeof(double);
case OperandType.InlineVar:
return sizeof(short);
case OperandType.ShortInlineBrTarget:
case OperandType.ShortInlineI:
case OperandType.ShortInlineVar:
return sizeof(byte);
case OperandType.ShortInlineR:
return sizeof(float);
default:
throw new InvalidOperationException();
}
}
}
public sealed class MethodBodyIL : IEnumerable<ILInstruction>
{
private readonly MethodBase method;
public MethodBodyIL(MethodBase method)
{
if (method == null)
throw new ArgumentNullException("method");
this.method = method;
}
public Enumerator GetEnumerator()
{
var body = this.method.GetMethodBody();
return new Enumerator(this.method.Module, this.method.DeclaringType.GetGenericArguments(), this.method.GetGenericArguments(), body.GetILAsByteArray(), body.LocalVariables);
}
IEnumerator<ILInstruction> IEnumerable<ILInstruction>.GetEnumerator()
{
return this.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
public struct Enumerator : IEnumerator<ILInstruction>
{
private static readonly IDictionary<short, OpCode> codes = typeof(OpCodes).FindMembers(MemberTypes.Field, BindingFlags.Public | BindingFlags.Static, (m, criteria) => ((FieldInfo)m).FieldType == typeof(OpCode), null).Cast<FieldInfo>().Select(f => (OpCode)f.GetValue(null)).ToDictionary(c => c.Value);
private readonly Module module;
private readonly Type[] genericTypeArguments, genericMethodArguments;
private readonly byte[] il;
private readonly IList<LocalVariableInfo> localVariables;
private int offset;
private ILInstruction current;
internal Enumerator(Module module, Type[] genericTypeArguments, Type[] genericMethodArguments, byte[] il, IList<LocalVariableInfo> localVariables)
{
this.module = module;
this.genericTypeArguments = genericTypeArguments;
this.genericMethodArguments = genericMethodArguments;
this.il = il;
this.localVariables = localVariables;
this.offset = 0;
this.current = default(ILInstruction);
}
public ILInstruction Current
{
get { return this.current; }
}
public bool MoveNext()
{
if (this.offset < this.il.Length)
{
this.current = this.ReadInstruction();
return true;
}
else
{
this.current = default(ILInstruction);
return false;
}
}
public void Reset()
{
this.offset = 0;
this.current = default(ILInstruction);
}
public void Dispose()
{
this.offset = this.il.Length;
this.current = default(ILInstruction);
}
private ILInstruction ReadInstruction()
{
var code = this.ReadCode();
return new ILInstruction(code, this.ReadOperand(code.OperandType));
}
private OpCode ReadCode()
{
var code = codes[this.ReadByte()];
if (code.OpCodeType == OpCodeType.Prefix)
code = codes[(short)(code.Value << 8 | this.ReadByte())];
return code;
}
private object ReadOperand(OperandType operandType)
{
switch (operandType)
{
case OperandType.InlineBrTarget:
case OperandType.InlineI:
case OperandType.InlineSwitch:
return this.ReadInt32();
case OperandType.InlineField:
case OperandType.InlineMethod:
case OperandType.InlineTok:
case OperandType.InlineType:
return this.ReadMember();
case OperandType.InlineI8:
return this.ReadInt64();
case OperandType.InlineNone:
return null;
case OperandType.InlineR:
return this.ReadDouble();
case OperandType.InlineSig:
return this.ReadSignature();
case OperandType.InlineString:
return this.ReadString();
case OperandType.InlineVar:
return this.ReadLocalVariable();
case OperandType.ShortInlineBrTarget:
case OperandType.ShortInlineI:
return this.ReadByte();
case OperandType.ShortInlineR:
return this.ReadSingle();
case OperandType.ShortInlineVar:
return this.ReadLocalVariableShort();
default:
throw new InvalidOperationException();
}
}
private byte ReadByte()
{
var value = this.il[this.offset];
++this.offset;
return value;
}
private short ReadInt16()
{
var value = BitConverter.ToInt16(this.il, this.offset);
this.offset += sizeof(short);
return value;
}
private int ReadInt32()
{
var value = BitConverter.ToInt32(this.il, this.offset);
this.offset += sizeof(int);
return value;
}
private long ReadInt64()
{
var value = BitConverter.ToInt64(this.il, this.offset);
this.offset += sizeof(long);
return value;
}
private float ReadSingle()
{
var value = BitConverter.ToSingle(this.il, this.offset);
this.offset += sizeof(float);
return value;
}
private double ReadDouble()
{
var value = BitConverter.ToDouble(this.il, this.offset);
this.offset += sizeof(double);
return value;
}
private MemberInfo ReadMember()
{
return this.module.ResolveMember(this.ReadInt32(), this.genericTypeArguments, this.genericMethodArguments);
}
private byte[] ReadSignature()
{
return this.module.ResolveSignature(this.ReadInt32());
}
private string ReadString()
{
return this.module.ResolveString(this.ReadInt32());
}
private LocalVariableInfo ReadLocalVariable()
{
return this.localVariables[this.ReadInt16()];
}
private LocalVariableInfo ReadLocalVariableShort()
{
return this.localVariables[this.ReadByte()];
}
object IEnumerator.Current
{
get { return this.Current; }
}
}
}
public static class ILHelper
{
public static MethodBodyIL GetIL(this MethodBase method)
{
return new MethodBodyIL(method);
}
public static IEnumerable<MethodBase> GetCalledMethods(this Delegate methodPtr)
{
if (methodPtr == null)
throw new ArgumentNullException("methodPtr");
foreach (var instruction in methodPtr.Method.GetIL())
if (IsMethodCall(instruction.Code))
yield return (MethodBase)instruction.Operand;
}
private static bool IsMethodCall(OpCode code)
{
return code == OpCodes.Call || code == OpCodes.Calli || code == OpCodes.Callvirt;
}
}
}
您可以使用method.Name获取调用方法名称。
public static class Invoker
{
public static void invoke(Proxy proxy, Func<Proxy, string> online)
{
//Some caching logic that require the name of the method
//invoked on the proxy (in this specific case "formatSomething")
var methodName = online.Method.Name;
}
}
https://msdn.microsoft.com/en-us/library/system.multicastdelegate%28v=vs.110%29.aspx