C#如何获取传入的匿名方法中的实际调用的方法

我想实现一个类似 Hangfire 的东西,在后台执行一些耗时的任务,有点不同的地方是,任务是在多个面向用户的轻量级服务器上发起的,然后由一个或多个专用服务器通过队列进行处理。

这里是我构想的一个入口方法

public void GetMethodInfo<T>(Func<T> value)

我想在传入的匿名方法里找到实际调用。

Eg

static void Main(string[] args)
{
    ClassA a = new ClassA();

    GetMethodInfo(()=>{ return a.GetXXXTableList(); })
    int pageIndex=1;
    int pageSize=10;
    int pageCount;
    GetMethodInfo(()=>{ return a.GetYYYTableList(pageIndex,pageSize,out pageCount); })
}

static void GetMethodInfo<T>(Func<T> value)
{
    //我想在这里获取到上面调用传入的方法a.GetXXXTableList或者a.GetYYYTableList
}

class ClassA
{
    public List<XXXDTO> GetXXXTableList()
    {
        List<XXXDTO> list = new List<XXXDTO>()//do anything
        //查询数据和其他工作
        return list;
    }
    public List<YYYDTO> GetYYYTableList(int pageIndex,int pageSize,out int pageCount)
    {
        pageCount = 0;
        List<YYYDTO> list = new List<YYYDTO>()//do anything
        //查询数据和其他工作
        return list;
    }
}

这个问题出现的原因是某些方法需要很长时间运行并且不需要高实时性。

我想通过传入的匿名方法获取实际在内部调用的方法。在每次传入的匿名函数里只会调用一种方法。
但是不同方法的参数不完全相同,所以不能通过创建多个通用委托实现,或者说这个只能当作最后的选择。

我尝试过以下方法

static void GetMethodInfo<T>(Func<T> value)
{

    StackFrame[] infm = null;
    value += () => { infm = new StackTrace().GetFrames(); T val = default; return val; };

    var name = value.Method.Name;

    var dataargs = value.GetType().GetGenericArguments();

    var dgls = value.GetInvocationList();
    var mti = value.GetMethodInfo();

    var methodResult = value.Invoke();

    StackFrame[] fms = new StackTrace().GetFrames();
    var fms1 = fms[fms.Length - 1].GetMethod().Name;
    var refmi = RuntimeReflectionExtensions.GetMethodInfo(value);
    Debugger.Break();
}

上面方法均不起作用 只能得到一个匿名方法的名称

//The information obtained is all 
<GetMethod1>b__0

我到目前为止还没有想到更优解, 下一步可能会试着从传入的参数和返回值为切入点,然后通过反射去Class里面查找方法
最后, 先感谢大家帮助, 如果大家有不错的思路的话不吝赐教
如果没有的话也请不要用AI生成的废话灌水
不要用AI生成的废话灌水
不要用AI生成的废话灌水
不要用AI生成的废话灌水
不要用AI生成的废话灌水

匿名方法每次获取是动态的嘛

【以下回答由 GPT 生成】

可以使用反射来解决这个问题。具体步骤如下:

  1. 使用 MethodBase.GetCurrentMethod() 方法获取当前方法的 MethodBase 对象。
MethodBase method = MethodBase.GetCurrentMethod();
  1. 使用 method.GetMethodBody().GetILAsByteArray() 方法获取当前方法的 IL 字节码。
byte[] ilBytes = method.GetMethodBody().GetILAsByteArray();
  1. 分析 IL 字节码,找到调用匿名方法的指令。

在 IL 字节码中,调用方法通过 call 指令来实现。匿名方法本质上是一个委托,所以需要找到调用委托的代码。根据 C# 的编译方式,调用委托的指令为 callvirtcall

// 搜索 IL 字节码,找到调用委托的指令
for (int i = 0; i < ilBytes.Length; i++)
{
    // callvirt 指令的操作码为 0x6f
    // call 指令的操作码为 0x28 或 0x29
    if (ilBytes[i] == 0x6f || ilBytes[i] == 0x28 || ilBytes[i] == 0x29)
    {
        // 找到了调用委托的指令,获取调用的方法元数据标记
        int token = BitConverter.ToInt32(ilBytes, i + 1);
        MethodInfo calledMethod = method.Module.ResolveMethod(token);

        // 调用的方法是 a.GetXXXTableList() 或者 a.GetYYYTableList()
        string methodName = calledMethod.Name;

        // 至此,我们获取到了实际调用的方法
        Console.WriteLine("调用的方法名: " + methodName);
        break;
    }
}

以上是实现的思路和代码示例。请注意,这种方式是通过分析 IL 字节码来获取调用的方法,所以对于一些特殊情况可能无法准确获取。另外,由于 IL 字节码的格式可能会有变化,所以确保在使用前进行适当的测试和验证。如果遇到复杂的情况,建议进一步研究更底层的机制来获取方法调用信息,比如使用调试器 API。



【相关推荐】



如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^
() => { ... };
这个方法是一个Lambda表达式

它的名字就是
<GetMethod1>b__0

这没有任何问题,这个方法是C#编译器产生的,本质上和你定义一个方法,在IL层面是同等待遇。

如果说你不希望匿名方法,强制要普通方法,可以用接口+方法代替委托。


确定么,我不确定。

()=>{ return a.GetXXXTableList(); }

因为我们无法得知,你就一定写成这样。

所以

```c#
()=>{ retrun 1+1}

``` 会如何呢??
如果是想统计那些方法的运行时间,然后进行优化限流,你应该从那些方法本身入手

当然如何想识别一个东西,我们依据是hash

所以可能会预先写好。
var b= ()=>{ return a.GetXXXTableList(); }

你说调用b,我知道b的hash,但我不知道里面是啥,所以我可以统计b的运行时间可以动态对b进行限流。如果你想知道是这个GetXXXTableList()有问题,请自己写日志记录。我们无法知道他是啥,除非你return的东西有其他附加信息
比如异步调用有一个 asyncResult的通用上下文对象,他就附加了一些基础元信息

反射是可以获取该动态方法

C#实现在匿名方法中捕获外部变量的方法
可以参考下
https://www.yii666.com/blog/102499.html

这段代码可以参考一下


static void Main(string[] args)
        {
            try
            {
                int param1 = 1;
                string param2 = "aa";
                string value = null;
                Func<int> a = () => Fun(param1, param2, out value);
                GetMethodName(a);
                
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            Console.ReadKey();
        }
        public static void GetMethodName<T>(Func<T> fun)
        {
            var dispalyClass = fun.GetMethodInfo().DeclaringType;
            var method = dispalyClass.GetRuntimeMethods().First();
            var ilBytes = method.GetMethodBody().GetILAsByteArray();
            for (int i = 0; i < ilBytes.Length; ++i)
            {
                if (ilBytes[i] == 0x6f || ilBytes[i] == 0x28 || ilBytes[i] == 0x29)
                {
                    int token = BitConverter.ToInt32(ilBytes, i + 1);
                    var calledMethod = method.Module.ResolveMethod(token);
                    string methodName = calledMethod.Name;
                    Console.WriteLine("调用的方法名: " + methodName);
                    break;
                }
            }
        }
        public static int Fun(int p1, string p2, out string value)
        {
            value = p2 + p1;
            Console.WriteLine(p1 + " " + p2);
            return p1 + 1;
        }

要实现你的需求,可以考虑是否可以使C#的反射机制来获取调用的方法信息。或取匿名方法的Target对象,然后通过该对象的GetType方法获取其类型,使用该类型调用其GetMethod方法,传入匿名方法的函数名

C#读取匿名对象的属性值的方法总结_weixin_30783913的博客-CSDN博客 目录 1、通过反射的方式获取属性值 2、新建个扩展方法,将object转成对应的匿名对象 通过new出匿名对象,可以直接调用该匿名对象的属性名,获取属性值。var objUser = new {Name="Lilei",Age=18 };//此时可直接读取匿名类属性Console...._c#获取json匿名对象的属性名 https://blog.csdn.net/weixin_30783913/article/details/98829807?ops_request_misc=&request_id=&biz_id=102&utm_term=C&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-1-98829807.142^v93^chatsearchT3_2&spm=1018.2226.3001.4187#%E5%A6%82%E4%BD%95%E8%8E%B7%E5%8F%96%E4%BC%A0%E5%85%A5%E7%9A%84%E5%8C%BF%E5%90%8D%E6%96%B9%E6%B3%95%E4%B8%AD%E7%9A%84%E5%AE%9E%E9%99%85%E8%B0%83%E7%94%A8%E7%9A%84%E6%96%B9%E6%B3%95&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-1-98829807.142^v93^chatsearchT3_2