我正在尝试在c#中执行类似于javascript的function.bind()的操作。
我有一个动作:
var action = new Action(()=>{this.SomeProperty = 123;});
在运行时,我想在不同的闭包中执行操作,因此实例“this”是一个动态对象。
类似的东西:
var action = new Action(()=>{this.SomeProperty = 123;});
dynamic myDynamic = new ExpandoObject();
myDynamic.SomeProperty=321;
action.Bind(myDynamic); <--Of course this does not work...
action.DynamicInvoke();
Console.WriteLine(myDynamic.SomeProperty); //Should write 123...
我开始认为这是不可能的,因为我正在学习关于lambdas和动力学的运行时如何工作..也许有一些方法使用反射?
由于 兰斯
非常感谢任何建议。
答案 0 :(得分:1)
你真的不需要做任何复杂的事情,你只需要采取一个动态参数。
Action<dynamic> method = new Action<dynamic>((obj) => obj.SomeProperty = 123);
然后,您可以使用任意数量的对象调用该操作(如果他们无法设置该属性,某些对象会明显抛出异常)
method(new ExpandoObject());
method(new object()); // exception
如果你想像你的例子一样调用它,它就像制作扩展方法一样简单:
public static class DynamicActionExtensions
{
public static void DynamicInvoke<T>(this T actual)
{
dynamic obj = actual;
obj.SomeProperty = 123;
}
}
编辑:这个怎么样:
public class Invoker
{
protected List<dynamic> _objects = null;
protected Action<dynamic> _method = null;
public Invoker()
{
_objects = new List<dynamic>();
}
public void Bind(dynamic actual)
{
_objects.Add(actual);
}
public void SetDelegate<T>(Action<T> action)
{
_method = action; // should work due to covariant type assignment
}
public void DynamicInvoke()
{
_objects.ForEach(x => _method(x));
}
}
Invoker x = new Invoker();
x.SetDelegate<SomeTypeForIntellisense>((obj) => obj.SomeProperty = 123);
x.Bind(new ExpandoObject());
x.DynamicInvoke();
答案 1 :(得分:0)
是否可以更改Action
的目标?不,因为Action
是不可变的。但是,可以相对轻松地使用相同的方法创建新的委托,但目标不同。
public static Action Bind(this Delegate d, object target)
{
return (Action) Delegate.CreateDelegate(typeof(Action), target, d.Method);
}
这对于不捕获变量的lambda来说效果很好:
Action a = () => this.MyProperty = 12;
a();
var f = new Foo();
var b = a.Bind(f);
b();
Console.WriteLine(this.MyProperty == f.MyProperty); // "True"
不幸的是,这似乎对您没有帮助,因为您希望在运行时更改目标的类型。由于编译器将目标类型烘焙到委托中,因此无法更改它。使用dynamic
会更糟糕,因为它会生成完全不同的代码来访问动态类型。
如果您愿意将自己限制在编译器将在Expression<>
中生成的内容,那么您将能够执行一些复杂的表达式树操作并使其工作。由于表达式树甚至不能具有赋值运算符,因此使用此方法也无法实现简单的示例。
我很确定无法让Intellisense 和能够对LINQ不允许的任何内容使用运行时(动态)绑定。