2

英語は私の母国語ではありません。私の質問が十分に明確になることを願っています。

実行時にどのアクションが Action クラスに含まれているか (正確にはどのプロパティが呼び出されるか) を識別する方法を知りたいです。

単純な Employee クラスを想像してみてください...

public class Employee
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Age { get; set; }
    public string Email { get; set; }
}

...そして、 Action<> をパラメーターとして受け取るシンプルな Update() メソッド

public static void Update(Action<Employee> action) {
    //HERE : how could i know which properties will be assigned by analyzing the Action<Employee> object ?

    Employee em = new Employee();

    action(em);

    //Only FirstName and LastName have been assigned to "em"
}

Update メソッドは次のように呼び出すことができます。

//Call the Update method with only two "actions" : assign FirstName and LastName properties.
Update(e => { e.FirstName = "firstname"; e.LastName = "lastname"; });

私の問題は、Update() メソッド内で、どのプロパティが Action<> オブジェクト内の割り当て (および関連する値) のために「計画」されているかを特定することです。

Action<> オブジェクトを分析して、プロパティ FirstName と LastName のみに値 "firstname" と "lastname" が割り当てられることをどのように発見できますか? まったく可能ですか?

これについては、GoogleとSOでヘルプが見つかりません。多分私は間違った方法で質問しています。

メッセージの最後には、実行/デバッグできるプログラム全体があります。

SOの皆さん、よろしくお願いします。

マイク

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TestAction
{
    class Program
    {
        public class Employee
        {
            public string FirstName { get; set; }
            public string LastName { get; set; }
            public int Age { get; set; }
            public string Email { get; set; }
        }

        static void Main(string[] args)
        {
            //Call the Update method with only two "actions" : assign FirstName and LastName properties.
            Update(e => { e.FirstName = "firstname"; e.LastName = "lastname"; });
        }

        public static void Update(Action<Employee> action)
        {
            //HERE : how could i know which properties will be assigned by analyzing the Action<Employee> object ?

            Employee em = new Employee();

            action(em);

            //Only FirstName and LastName have been assigned to "em"
        }
    }
}
4

4 に答える 4

1

デリゲートを分析できないことを認識させてくれた皆さんに感謝します(あなたの説明がなければ、私はまだ方法を理解しようとしていたでしょう...)。

私がやろうとしていたことを達成するには、プロパティ割り当てのリストを渡す可能性と、そのリストを分析する可能性が必要でした。あなたの助けを借りて、式ツリーのみを分析できるという結論に達しました。私はそのようにしました:

public static void Update<T>(Expression<Action<T>> action) where T : class

Update メソッド内で、式は標準の Visitor パターンで分析されます。割り当てられたプロパティと関連付けられた値を取得できます。

メソッドは次のように呼び出されます。

Update<Employee>(o => new Employee() { FirstName = "Mike", Email = "mike@so.com" });

助けてくれてありがとう!

マイク

于 2013-06-28T16:58:29.513 に答える
1

これは取り組むのが簡単な問題ではありませんが、本当にこの方法で行う必要がある場合は、が知っている方法を概説しましょう。

分解して解釈する

これには、実行時に実行する .NET (または x86/x64) 逆アセンブラーを取得し、それを問題のメソッドに向けてから、出力を分析して、ターゲット型のフィールドへのアクセスを探す必要があります。

これは難しいと思います。この手法から必要なものを得るには、MSIL と、場合によってはコンパイラで使用される最適化手法について十分に理解している必要があります。

アクセスを記録するプロキシ オブジェクトを使用する

アクション デリゲートに渡すプロキシ オブジェクトを作成できます。このプロキシ オブジェクトは、おそらくプロパティごとのブール変数に、各プロパティがアクセスされたことを記録します。その後、これらのブール値を調べて、どのプロパティがアクセスされたかを判断します。

これははるかに簡単です。クラスを仮想化し、各プロパティも仮想化し、子孫クラスを作成する必要があります。これは、Reflection.Emit または実行時に型を作成する他の方法を使用して行うことができます。

ただし、アクション デリゲートの対象となるメソッド内のすべてのコードを実際に実行する必要があり、これは望ましくない場合があります。

元のオブジェクトの通常のコピーを使用して、各プロパティにアクション デリゲートによって与えられないことがわかっているマジック値を与え、デリゲートを呼び出し、マジック値と現在の値の違いをチェックすることもできます (電話の後)。残念ながら、これにはデリゲートを呼び出す必要もあり、ターゲット オブジェクトでプロパティ セッターも実行する必要がありますが、どちらも望ましくない場合があります。

私の意見

私の意見では、これを行う別の方法を見つけた方がはるかに良いでしょう。これはより明確です。

于 2013-06-28T07:38:08.963 に答える
1

何が変更されたかは、インスタンスの現在の状態に関するものであるため、組み込みの方法で何が変更されたかを確認する方法はありません。例:

A {Name="Patrick"} //init 
A {Name = "Jane"} // changed from Patrick to Jane
A {Name = "Martin"} //changed from Jane to Martin

したがって、これを自分で管理する方法は他にありません。すべてのプロパティ セッターを追跡し、そのうちの 1 つがset呼び出し元によるものである場合は、変更されたプロパティの名前をオブジェクト リストのインスタンスのローカルに配置します。

呼び出しUpdate時に、変更されたプロパティの名前のリストをスクロールし、それらの値のみを取得して更新します (すべてリフレクションを介して)。その後、更新が成功したら、リストをクリーンアップします。

単なるアイデアですが、これを達成する他の方法もあるかもしれません。

于 2013-06-28T07:38:16.797 に答える
0

デリゲートを分析することはできません。分析するには、式ツリーが必要です。

public static void Update(Expression<Action<Employee>> action)

残念ながら、本体を含むラムダ式はコンパイラによって式ツリーに自動的に変換できないため、呼び出しごとに式を 1 つのプロパティに制限する必要があります。
さらに、代入演算子を含む式ツリーも自動的に変換できないため、別の方法を見つける必要があります。

于 2013-06-28T07:37:58.213 に答える