使用反射检测在 C# 方法中调用了哪个异步重载

问题描述

使用反射,我需要确定特定异步方法正在调用哪些重载。在这种情况下,我需要检查 DoSomething() 方法以确定它正在调用哪个方法调用 MyMethod()

首先,考虑以下用于同步版本的 C# 控制台应用程序:

using System;
using System.Linq;
using System.Reflection;
using Mono.Cecil;

namespace CecilReflection
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var assemblyDeFinition = AssemblyDeFinition.ReadAssembly(Assembly.GetExecutingAssembly().Location);

            var toInspect = assemblyDeFinition.MainModule
                .GetTypes()
                .SelectMany(type => type.Methods
                    .Where(method => method.HasBody)
                    .Select(method => new
                    {
                        Type = type,Method = method
                    }))
                .Where(x => x.Method.Name == "DoSomething");

            foreach (var entry in toInspect)
            {
                Console.WriteLine($"\tType = {entry.Type.Name}\n\t\tMethod = {entry.Method.Name}");
                foreach (var instruction in entry.Method.Body.Instructions)
                    Console.WriteLine($"{instruction.OpCode} \"{instruction.Operand}\"");
            }

            Console.ReadKey();
        }

        public static void DoSomething()
        {
            var myClass = new MyClass();

            myClass.MyMethod();
            myClass.MyMethod(5);
        }

        public class MyClass
        {
            public void MyMethod()
            {
            }

            public void MyMethod(int arg)
            {
            }
        }
    }
}

运行它会产生以下输出

        Type = Program
                Method = DoSomething
nop ""
newobj "System.Void CecilReflection.Program/MyClass::.ctor()"
stloc.0 ""
ldloc.0 ""
callvirt "System.Void CecilReflection.Program/MyClass::MyMethod()"
nop ""
ldloc.0 ""
ldc.i4.5 ""
callvirt "System.Void CecilReflection.Program/MyClass::MyMethod(system.int32)"
nop ""
ret ""

通过查看 callvirt 条目,我能够检测到使用上述代码调用MyMethod() 的两个重载。

这是异步版本:

using System;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using Mono.Cecil;

namespace CecilReflection
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var assemblyDeFinition = AssemblyDeFinition.ReadAssembly(Assembly.GetExecutingAssembly().Location);

            var toInspect = assemblyDeFinition.MainModule
                .GetTypes()
                .SelectMany(type => type.Methods
                    .Where(method => method.HasBody)
                    .Select(method => new
                    {
                        Type = type,Method = method
                    }))
                .Where(x => x.Method.Name == "DoSomething");

            foreach (var entry in toInspect)
            {
                Console.WriteLine($"\tType = {entry.Type.Name}\n\t\tMethod = {entry.Method.Name}");
                foreach (var instruction in entry.Method.Body.Instructions)
                    Console.WriteLine($"{instruction.OpCode} \"{instruction.Operand}\"");
            }

            Console.ReadKey();
        }

        public static async Task DoSomething()
        {
            var myClass = new MyClass();

            await myClass.MyMethodAsync();
            await myClass.MyMethodAsync(5);
        }

        public class MyClass
        {
            public async Task MyMethodAsync()
            {
            }

            public async Task MyMethodAsync(int arg)
            {
            }
        }
    }
}

这会产生以下输出

        Type = Program
                Method = DoSomething
newobj "System.Void CecilReflection.Program/<DoSomething>d__1::.ctor()"
stloc.0 ""
ldloc.0 ""
call "System.Runtime.CompilerServices.AsyncTaskMethodBuilder System.Runtime.CompilerServices.AsyncTaskMethodBuilder::Create()"
stfld "System.Runtime.CompilerServices.AsyncTaskMethodBuilder CecilReflection.Program/<DoSomething>d__1::<>t__builder"
ldloc.0 ""
ldc.i4.m1 ""
stfld "system.int32 CecilReflection.Program/<DoSomething>d__1::<>1__state"
ldloc.0 ""
ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder CecilReflection.Program/<DoSomething>d__1::<>t__builder"
ldloca.s "V_0"
call "System.Void System.Runtime.CompilerServices.AsyncTaskMethodBuilder::Start<CecilReflection.Program/<DoSomething>d__1>(!!0&)"
ldloc.0 ""
ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder CecilReflection.Program/<DoSomething>d__1::<>t__builder"
call "System.Threading.Tasks.Task System.Runtime.CompilerServices.AsyncTaskMethodBuilder::get_Task()"
ret ""

对于异步版本,我无法确定调用MyMethodAsync() 的哪些重载(如果有)。

有什么方法可以确定调用MyMethodAsync() 的哪些重载?我不要求使用 Mono.Cecil,但使用 System.Reflection 来完成此操作的运气更差。如果完全不同的方法可行,那很好。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)