1

Ich möchte diesen Test bestehen:Wie man Expression.Lambda an irgendeinen Besitzertyp anfügt?

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

Dies ist notwendig Stack-Fuß lagacy Code korrekt arbeiten kann. Was ist der einfachste Weg?

Ich würde den portabelsten Weg bevorzugen.

+0

Ist es eine Option für Sie, einen neuen Typ zur Laufzeit zu erstellen? –

+0

@YacoubMassad ja, aber ich würde die beweglichste Methode bevorzugen – Vlad

Antwort

3

Sie können zur Laufzeit einen neuen Typ erstellen und den Ausdruck dann in eine Methode dieses Typs kompilieren.

Sie müssen zur Laufzeit eine neue Baugruppe und ein neues Modul erstellen. Sobald Sie diese erstellt haben, können Sie sie verwenden, um so viele Typen wie Sie möchten zu erstellen. Hier ist ein Codebeispiel die Montage und das Modul zu erstellen:

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

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

Nun können Sie das Modul-Builder verwenden, um einen neuen Typ wie folgt zu definieren:

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

und dann eine neue Methode wie folgt :

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

Bitte beachten Sie, dass die Methodensignatur Ihren Ausdruck Delegattyp übereinstimmen sollte.

Als nächstes erstellen wir den Ausdruck in der neuen Methode unter Verwendung des CompileToMethod Methode:

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

expression.CompileToMethod(methodBuilder); 

Wir erzeugen den tatsächlichen Typ vom Typ Bauer:

var type = typeBuilder.CreateType(); 

Dann verwenden wir die Delegate.CreateDelegate Methode Erstellen Sie einen Delegaten für die neu erstellte statische Methode wie folgt:

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

int value = func(); //Test 

Jetzt würde func.Method.DeclaringType unseren dynamisch erstellten Typ zurückgeben.

Sie können diesen Code verwenden, um einige Hilfsmethoden zu generieren, um die Verwendung zu vereinfachen.

+0

Wissen Sie, ob es funktioniert.NET Core oder Portable Frameworks? – Vlad

+0

Ich bin mir nicht sicher. Warum nicht testen? –

+0

Schön! Ich habe nicht einmal darüber nachgedacht. Ich werde das definitiv umsetzen! – MichaelDotKnox

1

Ok, ich habe es selbst gefunden, aber ich bin mir nicht sicher, wie es in .NET Core funktioniert und welches Framework das unterstützt oder nicht. Wenn Sie eine bessere (elegantere oder tragbare) Lösung haben, können Sie Ihre Antwort gerne posten.

Der Schlüssel ist CompileToMethod von Lambda Ausdruck zu verwenden.

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