Mono.从作为泛型参数传递的委托中获取方法引用



我试图了解哪些具体类型在IOC(依赖注入)容器中提供接口的实现。当不涉及委托时,我的实现工作得很好。然而,当委托方法作为类型工厂传递时,我遇到了麻烦,因为我无法获得Mono。Cecil给我具体的类型或方法参考工厂回来。在这种情况下,我特别尝试构建一个可以与。net ASP的IServiceCollection容器一起工作的组件。Net REST api。我在下面创建了一组"最小化"的代码,以便于解释这个问题。

考虑下面的c#代码:

interface IServiceProvider {}
interface IServiceCollection {}
class ServicesCollection : IServiceCollection {}
interface IMongoDBContext {}
class MongoDBContext : IMongoDBContext
{
public MongoDBContext(string configName) {}
}
static class Extensions
{
public static IServiceCollection AddSingleton<TService>(this IServiceCollection services, Func<IServiceProvider, TService> implementationFactory) where TService : class
{
return null;
}
}
class Foo
{
void Bar()
{
IServiceCollection services = new ServicesCollection();
services.AddSingleton<IMongoDBContext>(s => new MongoDBContext("mongodbConfig"));
}
}

成功定位"服务"时。AddSingleton'作为MethodReference,我无法看到任何对MongoDBContext类或其构造函数的引用。当打印所有的指令。tostring()时,我似乎在IL中也看不到任何东西-我确实看到编号的参数为!!0,但是如果我不能将其解析为类型或工厂方法,那就没有帮助了。

谁有解决这个问题的办法?

很可能你的代码找错地方了。

c#编译器将尝试缓存lambda expression->delegate.

如果你看sharplab。你会看到编译器在你的Foo类中发出一个内部类'<>c',在这个类中它发出方法'<Bar>b__0_0',它将作为委托传递(见操作码ldftn)。

我不认为有一种简单而不脆弱的方法可以找到这个方法。

也就是说,一个选项是:

  1. 查找AddSingleton()方法调用
  2. 从那里开始返回到前面的指令,试图确定哪一条正在推入1中消耗的值(最安全的方法是考虑您访问的每条指令如何更改堆栈)。在我链接的代码中,它将是Bar()方法的IL_0021(dup)。
  3. 从那里,做一些类似于2的事情,但现在寻找Func<T, R>的ctor使用的方法引用(ldftn)的指令;在链接的代码中,应该是IL_0016
  4. 现在你可以检查主体(在链接的代码中,Foo/'<>c'::'<Bar>b__0_0')

注意这个实现有一些漏洞;例如,如果你像我一样用变量/参数/字段调用AddSingleton()(services.AddSingleton(_func);),你需要跟踪它的初始化以找到引用的方法。

有趣的是,在某些时候Cecil项目确实支持流分析(https://github.com/mono/cecil-old/tree/master/flowanalysis)。

如果你可以访问源代码,我认为使用Roslyn来分析它(而不是分析程序集)会更容易。

最新更新