1

Я хочу, чтобы этот тест пройти:Как присоединить Expression.Lambda к любому типу владельца?

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

Это необходимо сделать стек ходить lagacy кода для правильной работы. Какой самый простой способ сделать это?

Я предпочел бы самый портативный способ.

+0

Возможно ли вам создать новый тип во время выполнения? –

+0

@YacoubMassad да, но я бы предпочел самый портативный способ – Vlad

ответ

3

Вы можете создать новый тип во время выполнения и затем скомпилировать выражение в метод такого типа.

Вам нужно создать новую сборку и новый модуль во время выполнения. Создав их, вы можете использовать их для создания как можно большего количества типов. Вот пример кода для создания сборки и модуля:

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

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

Теперь вы можете использовать модуль строитель, чтобы определить новый тип, как это:

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

а затем новый метод, как это :

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

Обратите внимание, что подпись метода должна соответствовать типу делегата выражения.

Далее мы составляем выражение в новый метод с использованием CompileToMethod метода:

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

expression.CompileToMethod(methodBuilder); 

Мы генерируем фактический тип от типа строителя:

var type = typeBuilder.CreateType(); 

Затем мы используем метод Delegate.CreateDelegate для создайте делегата только что созданному статическому методу:

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

int value = func(); //Test 

Теперь func.Method.DeclaringType вернет наш динамически созданный тип.

Вы можете легко использовать этот код для создания некоторых вспомогательных методов, чтобы упростить его использование.

+0

Знаете ли вы, будет ли это работать.NET Core или Portable frameworks? – Vlad

+0

Я не уверен. Почему бы не проверить его? –

+0

Ницца! Я даже об этом не думал. Определенно собираюсь реализовать это! – MichaelDotKnox

0

Выражение лямбда компилируется в DynamicMethod, который всегда равен null для свойства DeclaringType.

См DynamicMethod definition

См this SO answer also

бы сделать свою жизнь проще, а если бы я мог найти способ обойти это.

1

Хорошо, я нашел его сам, но я не уверен, как он будет работать в .NET Core и какая инфраструктура может поддерживать или не поддерживать это. Если у вас есть лучшее (более элегантное или портативное) решение, не стесняйтесь публиковать свой ответ.

Ключ предназначен для использования CompileToMethod из Lambda.

[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)); 
}