简体   繁体   English

如何将Expression.Lambda附加到任何所有者类型?

[英]How to attach Expression.Lambda to ANY owner type?

I want this test to pass: 我希望此测试通过:

[Test]
public void LambdaTest()
{
    var m = Expression.Lambda(typeof(Func<int>), Expression.Constant(0)).Compile();
    Assert.That(m.Method.DeclaringType, Is.Not.Null);
}

This is necessary to make stack-walking lagacy code to work correctly. 这是使堆栈遍历延迟代码正常工作所必需的。 What's the simpliest way to do it? 最简单的方法是什么?

I would prefer the most portable way. 我希望使用最便携的方式。

You can build a new type at runtime and then compile the expression into a method of that type. 您可以在运行时构建新类型,然后将表达式编译为该类型的方法。

You need to create a new assembly and a new module at run time. 您需要在运行时创建一个新的程序集和一个新的模块。 Once you create those, you can use them to create as many types as you like. 创建这些类型后,就可以使用它们来创建任意数量的类型。 Here is a code sample to create the assembly and the module: 这是创建程序集和模块的代码示例:

var assemblyBuilder =
    AppDomain.CurrentDomain.DefineDynamicAssembly(
        new AssemblyName {Name = "MyNewAssembly"},
        AssemblyBuilderAccess.Run);

var moduleBuilder = assemblyBuilder.DefineDynamicModule("MyNewModule");

Now, you can use the module builder to define a new type like this: 现在,您可以使用模块构建器来定义新的类型,如下所示:

var typeBuilder = moduleBuilder.DefineType("MyNewType"); 

And then a new method like this: 然后是这样的新方法:

var methodBuilder = 
    typeBuilder.DefineMethod(
        "MyNewMethod",
        MethodAttributes.Public | MethodAttributes.Static,
        typeof(int), //returns an int
        new Type[]{}); //takes no parameters

Please note that the method signature should match your expression delegate type. 请注意,方法签名应与您的表达式委托类型匹配。

Next, we compile the expression into the new method using the CompileToMethod method: 接下来,我们使用CompileToMethod方法将表达式编译为新方法:

var expression = Expression.Lambda(typeof(Func<int>), Expression.Constant(0));

expression.CompileToMethod(methodBuilder);

We generate the actual type from the type builder: 我们从类型生成器生成实际类型:

var type = typeBuilder.CreateType();

Then we use the Delegate.CreateDelegate method to create a delegate to the newly created static method like this: 然后,我们使用Delegate.CreateDelegate方法创建新创建的静态方法的委托,如下所示:

Func<int> func =
    (Func<int>)Delegate.CreateDelegate(
        typeof(Func<int>),
        type.GetMethod("MyNewMethod"));

int value = func(); //Test

Now func.Method.DeclaringType would return our dynamically created type. 现在func.Method.DeclaringType将返回我们动态创建的类型。

You can easily use this code to generate some helper methods to make it easy to use. 您可以轻松地使用此代码生成一些帮助程序方法,以使其易于使用。

Ok, I found it myself but I'm not sure how it will work in .NET Core and which framework may or may not support this. 好的,我自己找到了它,但是我不确定它在.NET Core中如何工作,以及哪个框架可能支持也可能不支持。 If you have a better (more elegant or portable) solution please feel free to post your answer. 如果您有更好的解决方案(更优雅或更便携),请随时发布答案。

The key is to use CompileToMethod of Lambda expression. 关键是使用Lambda表达式的CompileToMethod

[Test]
public void LambdaTest2()
{
    var asm = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("test"), AssemblyBuilderAccess.Run);
    var masm = asm.DefineDynamicModule("main");

    var type = masm.DefineType("TestType");
    var mb = type.DefineMethod("TestMethod", MethodAttributes.Public | MethodAttributes.Static, typeof(int), new Type[0]);

    // your lambda
    ConstantExpression expressionTree = Expression.Constant(0);
    Expression.Lambda(typeof(Func<int>), expressionTree).CompileToMethod(mb);

    var m = (Func<int>)Delegate.CreateDelegate(typeof(Func<int>), type.CreateType().GetMethod("TestMethod"));

    Assert.That(m.Method.DeclaringType, Is.Not.Null);

    // you can create another in the same module but with another type (because type can't be changed)
    var type2 = masm.DefineType("TestType2");
    var mb2 = type2.DefineMethod("TestMethod2", MethodAttributes.Public | MethodAttributes.Static, typeof(int), new Type[0]);

    // your lambda 2
    ConstantExpression expresisonTree2 = Expression.Constant(1);
    Expression.Lambda(typeof(Func<int>), expresisonTree2).CompileToMethod(mb2);

    var m2 = (Func<int>)Delegate.CreateDelegate(typeof(Func<int>), type2.CreateType().GetMethod("TestMethod2"));

    Assert.That(m2.Method.DeclaringType, Is.Not.Null);

    // check correctness
    Assert.That(m(), Is.EqualTo(0));
    Assert.That(m2(), Is.EqualTo(1));
}

A lambda expression compiles to a DynamicMethod, which is always null for the DeclaringType property. Lambda表达式编译为DynamicMethod,对于DeclaringType属性,该方法始终为null。

See DynamicMethod definition 请参见DynamicMethod定义

See this SO answer also 也看到这个答案

Would make my life easier as well if I could find a way around that. 如果我能找到解决方法,那也会使我的生活更轻松。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM