4

私はこのc#コードを持っています:

Console.Writeline("Hello World");

これを DLR 式で行う場合は、次のようになります。

MethodInfo method = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(String) });
Expression callExpression = Expression.Call(null, method, Expression.Constant("Hello   World"));
Action callDelegate = Expression.Lambda<Action>(callExpression).Compile();
callDelegate();

この例は、本 Pro DLR in .NET 4 から引用しました。なぜこの余分な作業を行っているのか理解できません。Book によると、コードがメモリ内のオブジェクトとして表現されると、IL 命令よりもはるかに簡単に分析できるからです。

最も混乱するのは、コードに ConsoleWriteline() メソッドの代わりに DLR 式を配置してコンソール アプリケーションを実行すると、同じ .exe ファイル (CIL コードを含む) が取得され、"Hello world" が記述されたファイルが表示されることです。 .exe ファイルが実行された結果としてのコンソール。どちらの場合も、実行される .exe ファイル (cil コード) を取得しますが、実行時にコードをデータとして表すオブジェクトがどこにあり、どのようにアクセスすればよいかわかりません。

4

3 に答える 3

3

基本的に、2番目のコードスニペットが実行しているのは、呼び出しを式ツリーとしてカプセル化することです。式ツリーは.NETにとって比較的新しいものであり(メモリ内オブジェクト以外のデータメカニズムとのLinq相互運用機能を実装するために必要でした)、プログラム命令を変更可能でありながら実行可能な形式でカプセル化します。

必要に応じて、式を取得したら、Callノードによって参照されるConstantノードの値を変更することにより、出力されるテキストを「HelloWorld」から「HelloDolly」に変更できます。別のMethodInfoを使用するようにCallノードを変更できます。たとえば、Debug.WriteLine()または開発したカスタムWriteToLog()メソッドの呼び出しです。また、その式を渡して保存し、シリアル化して、この単純な例よりもはるかに先に呼び出すこともできます。これらの変更と決定はすべて、コンパイル時に不明な情報に基づいて実行時に行うことができます。動的に構築された式ツリーは、ファイルまたはデータベース内のデータに基づいて作成できます。これは変更が簡単で、この行を含むDLLまたはEXEの新しいバージョンをリリースする必要はありません。

対照的に、Console.WriteLine()の「静的」呼び出しは、コンパイル時にのみ変更でき(非常に厄介なILを送信する動的コードの可能性があるにもかかわらず)、その文字列が書き込まれる場所の要件がある場合は、そのような変更が必要です。変化する。

于 2011-03-17T16:28:29.380 に答える
1

実行時にコードをデータとして表すオブジェクトがどこにあるのか、またそれらにアクセスするにはどうすればよいのかわかりません。

Expressionコードをデータとして表すのはです。これは、 " のみの引数として Console.WriteLine メソッドへの呼び出しを表します。"Hello World

実行時にこの事実を発見する例を次に示します。

var method = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(String) });
var callExpression = Expression.Call(null, method, Expression.Constant("Hello   World"));

var expression = Expression.Lambda<Action>(callExpression);  

// Now let's try to inspect 'expression'

var body = expression.Body as MethodCallExpression;

if (body != null)
{
    Console.WriteLine("Expn's body is a method-call expn.");    
    Console.WriteLine("...that calls:" + body.Method.Name);

    var args = body.Arguments;

    if (args.Any())
    {
        Console.WriteLine("The call has arguments.");    

        var firstArg = args.First() as ConstantExpression;

        if (firstArg != null)
        {
            Console.WriteLine("The first argument is a constant expn.");
            Console.WriteLine("...with value " + firstArg.Value);
        }
    }
}
于 2011-03-17T16:22:57.980 に答える
1

余談ですが、式を生成する別の方法は次のとおりです。

Expression<Action> e=()=>Console.WriteLine("Hello World");

これにより、ボイラープレート リフレクション コードを記述する必要がなくなります。

于 2011-03-21T08:59:02.297 に答える