如何从UnaryExpression获取调用者实例?

时间:2014-07-06 08:38:27

标签: c# expression

我想有一个方法为Action<sender,args>创建一个包装器,所以当我想通过这个包装器调用这个动作时,我可以检查调用者是否为null。

以下是我创建包装器的方法:

public void Subscribe<TEventArgs>(Expression<Func<Action<object,TEventArgs>> expression)
{
    wrapper=new EventHandlerWrapper{Expression=expression};
    Subscribe<TEventArgs>(wrapper.GetHandler());
}

因此我可以这样称呼这个方法:

    var handler=new MyHandler();
    Subscribe(()=>handler.EventHandler);

然后我希望能够使用表达式

获取调用者实例(上面代码中的处理程序)

我传递的表达式是UnaryExpresison。我可以找到很多解决方案来说明我们如何从MemberExpression获取调用者但是在这里我无法抓住任何MemberExpression 1}}。我有一个UnaryExpression,其OperandMethodCallExpression,作为回报,ObjectConstantExpression,我被困在这里。 如何获取调用者实例?

更新

顺便说一句,EventHandler不是动作本身就是这样的方法:

public class MyHandler
{
    public void EventHandler(object sender,EventArgs e)
    {
              .....
    }
}

以下是Wrapper.GetHandler()的签名:

 public Action<object, TArgs> GetHandleAction()
        {
            return (sender, args) =>
            {
                if (Handler != null)
                {
                    HandlerExpression.Compile()();
                }
            };
        }

Handler是我想使用给定表达式填充它的调用者实例。

让问题清晰:我想从Expression<Func<Action<object,object>>获取来电者实例。

2 个答案:

答案 0 :(得分:1)

你可以这样:

var member = (((expression.Body as UnaryExpression).Operand as MethodCallExpression).Arguments[1] as MemberExpression);
var constant = (member.Expression as ConstantExpression);
var f = member.Member;

if ((f is FieldInfo))
{
     // here is your caller instance, do your checks.
     var callerInstance = ((FieldInfo)f).GetValue(constant.Value);
}

(基于:How to get Property Value from MemberExpression without .Compile()?

答案 1 :(得分:1)

在您给出的这个非常具体的示例中,您可以使用以下命令从表达式中提取handler

private static void Subscribe<TEventArgs>(Expression<Func<Action<object, TEventArgs>>> expression)
{
    var accessor = ((MethodCallExpression)((UnaryExpression)expression.Body).Operand).Arguments[1];
    var handlerFunc = Expression.Lambda<Func<object>>(accessor).Compile();
    var handler = handlerFunc();
    // handler now contains the instance you're interested in
}

如果您可以确保拨打Subscribe的电话始终是您提供的表格,那么这应该有效,但它非常脆弱。

还值得存储handlerFunc而不是handler,因为对Subscribe<EventArgs>(() => handler.EventHandler)的调用会创建一个捕获handler变量的闭包,它的价值。因此,如果您要将handler设置为null,或者在调用Subscribe后将其设置为其他值,则会调用新值EventHandler ,而不是Subscribe电话时的价值。