リフレクション ツリーと式ツリーを組み合わせて使用しており、特定のプロパティ アクセサーをクラスから呼び出し元のメソッドに戻したいと考えています。私の現在のコードには、クラスをトラバースして s のリストを返すメソッドがありMemberExpression
ます。次に、呼び出し元はメンバー式を反復処理し、ラムダを作成します。ラムダは、検査されたクラスのインスタンスで呼び出され、プロパティの値を返します。
メソッド呼び出しがない場合の例を次に示します (LINQPad で実行可能)。
void Main()
{
var t = new Test { Prop = "Test" };
var property = t.GetType().GetProperty("Prop");
var baseType = Expression.Parameter(typeof(Test), "baseType");
var memberAccess = Expression.MakeMemberAccess(baseType, property);
var lambda = Expression.Lambda<Func<Test, string>>(memberAccess, Expression.Parameter(typeof(Test), "baseType"));
var func = lambda.Compile();
var result = func(t);
result.Dump();
}
class Test {
public string Prop { get; set; }
}
これは機能せず、次の例外がスローされます。
InvalidOperationException: タイプ 'UserQuery+Test' の変数 'baseType' がスコープ '' から参照されましたが、定義されていません
ただし、ラムダの作成を次のように変更すると:
var lambda = Expression.Lambda<Func<Test, string>>(memberAccess, baseType);
つまり、Expression.Parameter
を以前に使用した変数に置き換えると、機能します。リストと一緒に元のパラメーターを返す必要があるため、これを使用したいシナリオでは (簡単に) 可能ではありません (もちろん、タプルを返すこともできますが、必要はありません)。
なぜこのように機能するのですか?ラムダの を検査するDebugView
と、どのアプローチが使用されても、それらはまったく同じです。
.Lambda #Lambda1<System.Func`2[UserQuery+Test,System.String]>(UserQuery+Test $baseType)
{
$baseType.S
}