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コアまたはポータブルフレームワーク? – Vlad

+0

わかりません。なぜそれをテストしないのですか? –

+0

ニース!私はそれについても考えなかった。間違いなくこれを実装しよう! – MichaelDotKnox

0

ラムダ式はDynamicMethodにコンパイルされますが、DeclaringTypeプロパティでは常にnullになります。

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)); 
} 
関連する問題