プロパティラムダをデリゲートに変換するメソッドを作成しました。
public static Delegate MakeGetter<T>(Expression<Func<T>> propertyLambda)
{
var result = Expression.Lambda(propertyLambda.Body).Compile();
return result;
}
public static Delegate MakeSetter<T>(Expression<Action<T>> propertyLambda)
{
var result = Expression.Lambda(propertyLambda.Body).Compile();
return result;
}
これらの作業:
Delegate getter = MakeGetter(() => SomeClass.SomeProperty);
object o = getter.DynamicInvoke();
Delegate getter = MakeGetter(() => someObject.SomeProperty);
object o = getter.DynamicInvoke();
しかし、これらはコンパイルされません:
Delegate setter = MakeSetter(() => SomeClass.SomeProperty);
setter.DynamicInvoke(new object[]{propValue});
Delegate setter = MakeSetter(() => someObject.SomeProperty);
setter.DynamicInvoke(new object[]{propValue});
MakeSetterの行が失敗し、「型引数は使用法から推測できません。型引数を明示的に指定してください。」
私がやろうとしていることは可能ですか?前もって感謝します。
Expression
APIは.NET 4.0でこれをサポートしますが、悲しいことに、C#コンパイラはサポートに追加のキャンディーを追加しません。しかし、朗報は、 "C"コンパイラcanで記述された "get"式を簡単に取得して、 "set"式として書き直すことができることです。
そしてさらに良い。 .NET 4.0がない場合でも、「取得」として記述された式を介して「設定」を実行する方法は、他に2つあります少なくとも。
ここにそれらはすべて情報です:
using System;
using System.Linq.Expressions;
using System.Reflection;
class Foo {
public string Bar { get; set; }
static void Main() {
// take a "get" from C#
Expression<Func<Foo, string>> get = foo => foo.Bar;
// re-write in .NET 4.0 as a "set"
var member = (MemberExpression)get.Body;
var param = Expression.Parameter(typeof(string), "value");
var set = Expression.Lambda<Action<Foo, string>>(
Expression.Assign(member, param), get.Parameters[0], param);
// compile it
var action = set.Compile();
var inst = new Foo();
action(inst, "abc");
Console.WriteLine(inst.Bar); // show it working
//==== reflection
MethodInfo setMethod = ((PropertyInfo)member.Member).GetSetMethod();
setMethod.Invoke(inst, new object[] { "def" });
Console.WriteLine(inst.Bar); // show it working
//==== Delegate.CreateDelegate
action = (Action<Foo, string>)
Delegate.CreateDelegate(typeof(Action<Foo, string>), setMethod);
action(inst, "ghi");
Console.WriteLine(inst.Bar); // show it working
}
}
私のコメントのとおり-リンクが機能しなくなったため-質問への回答として完全なコードを投稿しました。 はい、OPが要求していることを実行できます。そして、ここにそれを示すニックからの素敵な小さな宝石があります。ニックは、このページと彼の完全なソリューションとパフォーマンスメトリックの別のページを評価しています。 単なるリンク の代わりに以下を提供します。
// returns property getter
public static Func<TObject, TProperty> GetPropGetter<TObject, TProperty>(string propertyName)
{
ParameterExpression paramExpression = Expression.Parameter(typeof(TObject), "value");
Expression propertyGetterExpression = Expression.Property(paramExpression, propertyName);
Func<TObject, TProperty> result =
Expression.Lambda<Func<TObject, TProperty>>(propertyGetterExpression, paramExpression).Compile();
return result;
}
// returns property setter:
public static Action<TObject, TProperty> GetPropSetter<TObject, TProperty>(string propertyName)
{
ParameterExpression paramExpression = Expression.Parameter(typeof(TObject));
ParameterExpression paramExpression2 = Expression.Parameter(typeof(TProperty), propertyName);
MemberExpression propertyGetterExpression = Expression.Property(paramExpression, propertyName);
Action<TObject, TProperty> result = Expression.Lambda<Action<TObject, TProperty>>
(
Expression.Assign(propertyGetterExpression, paramExpression2), paramExpression, paramExpression2
).Compile();
return result;
}
Action<T>
は、T
型のパラメーターを1つ取り、何も返さないデリゲートを表します。 MakeSetter
に指定するラムダ式は、パラメーターをとらず、SomeClass.SomeProperty
またはsomeObject.SomeProperty
を返すデリゲートを表します。
受け取ったエラーメッセージは、コンパイラがMakeSetter
メソッドに渡したラムダ式から型を推測できないためです。同期中。
あなたのMakeSetter
はAction<T>
を期待していますが、あなたはそれにFunc<T>
(() => someObject.SomeProperty
)を渡しています。以下を試してください:
Delegate setter = MakeSetter((prop) => {someObject.SomeProperty = prop;});
setter.DynamicInvoke(new object[]{propValue});
[〜#〜] edit [〜#〜]できません ステートメントのラムダを式に変換してください 。これは、表現なしでそれを行うためのラウンドラウンドの方法です-デリゲートに直接:
class Test2 {
delegate void Setter<T>(T value);
public static void Test() {
var someObject = new SomeObject();
Setter<string> setter = (v) => { t.SomeProperty = v; };
setter.DynamicInvoke(new object[]{propValue});
}
}