【问题标题】:How to get the caller instance from an UnaryExpression?如何从 UnaryExpression 中获取调用者实例?
【发布时间】:2014-07-06 19:49:10
【问题描述】:

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

这是我创建包装器的方式:

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。我有一个UnaryExpression,它的Operand 是一个MethodCallExpression,作为回报,它的Object 是一个ConstantExpression,我被困在这里。 如何获取调用者实例?

更新:

顺便说一句,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&lt;Func&lt;Action&lt;object,object&gt;&gt; 获取调用方实例。

【问题讨论】:

  • 对于完整的图片,我们错过了这一行中的 GetHandler() 和订阅定义:“Subscribe(wrapper.GetHandler());
  • @qbik 我会将它们添加到我的问题中
  • 如果您将实际的、可编译的代码放入问题中,将会非常有帮助。实际上,代码存在很多问题,以至于您甚至不清楚您要做什么。例如。 Subscribe 似乎是无限递归的,除非你还没有给出另一个重载,并且 wrapper 是一个字段,或者你是否忘记将 var 放在它前面。此外,在您给出Wrapper.GetHandler() 的签名的地方,该方法实际上称为GetHandleAction()。请检查您的问题,并确保包含的代码实际编译并尽可能接近您使用的代码。
  • @Iridium 我编辑了我的问题并用一个简单的句子提出。

标签: c# expression


【解决方案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()?

【讨论】:

    【解决方案2】:

    在您给出的这个非常具体的示例中,您可以使用以下表达式从表达式中提取 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&lt;EventArgs&gt;(() =&gt; handler.EventHandler) 的调用会创建一个捕获handler 变量的闭包,不是它的值。因此,如果您将handler 设置为null,或在调用Subscribe 后设置为不同的值,则将调用新值的EventHandler,而不是调用时的值Subscribe 电话。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-12
      • 2019-07-08
      • 2019-07-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多