【发布时间】:2019-11-01 10:59:00
【问题描述】:
考虑一下这段简单的代码。 如何使用表达式树来做到这一点?
ErrorsChangedEventManager.AddHandler(obj, obj.SomeHandler);
这是一个小示例,说明了我要完成的工作。 (添加对WindowBase 的引用以使其编译。)
class Program : INotifyDataErrorInfo
{
public int Id { get; set; }
static void Main(string[] args)
{
var p1 = new Program { Id = 1 };
var p2 = new Program { Id = 2 };
// Here is the root of the problem.
// I need to do this INSIDE the expression from a given instance of Program.
EventHandler<DataErrorsChangedEventArgs> handler = p1.OnError;
var handlerConstant = Expression.Constant(handler);
var mi = typeof(ErrorsChangedEventManager).GetMethod(nameof(ErrorsChangedEventManager.AddHandler),
BindingFlags.Public | BindingFlags.Static);
var source = Expression.Parameter(typeof(INotifyDataErrorInfo), "source");
var program = Expression.Parameter(typeof(Program), "program");
// This will work, but the OnError method will be invoked on the wrong instance.
// So, I need to get the expression to perform what would otherwise be easy in code...
// E.g. AddHandler(someObject, p2.OnError);
var call = Expression.Call(mi, source, handlerConstant);
var expr = Expression.Lambda<Action<INotifyDataErrorInfo, Program>>(call, source, program);
var action = expr.Compile();
action.DynamicInvoke(p1, p2);
p1.ErrorsChanged.Invoke(p1, new DataErrorsChangedEventArgs("Foo"));
}
void OnError(object sender, DataErrorsChangedEventArgs e)
{
if (sender is Program p)
{
Console.WriteLine($"OnError called for Id={Id}. Expected Id=2");
}
}
public IEnumerable GetErrors(string propertyName) => Enumerable.Empty<string>();
public bool HasErrors => false;
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
}
显然,它不起作用。我需要以某种方式提供OnError 处理程序作为调用的参数。
【问题讨论】:
-
在创建
Expression.Lambda时,您从EventHandler<DataErrorsChangedEventArgs>切换到DataErrorsChangedEventArgs。留在EventHandler<DataErrorsChangedEventArgs>,你应该没事吧? -
我还缺少一些东西。 lambda 的创建失败:
System.ArgumentException: 'ParameterExpression of type 'System.ComponentModel.INotifyDataErrorInfo' cannot be used for delegate parameter of type 'System.Object'' -
您的
source参数是Program类型,因此您的Action需要是Action<Program, EventHandler<DataErrorsChangedEventArgs>>(为了更通用,您的source应该是typeof(INotifyDataErrorInfo),并且你的Action应该是Action<INotifyDataErrorInfo, EventHandler<DataErrorsChangedEventArgs>> -
好吧,如果我可以在代码中使用
p.OnError,那么我就可以构建一个 lambda。问题是为“p.OnError”构建表达式树,给定一个类型为“Program”的参数,对于任何实例...... -
我不关注。你能举例说明你想如何使用它吗?
标签: c# lambda expression-trees