【问题标题】:How to intercept a delegate call by using a class如何使用类拦截委托调用
【发布时间】:2015-11-18 23:33:40
【问题描述】:

基本上,我想要归档的是拦截对代表的调用的方法。我正在考虑定义一个可以用于它的类。比如:

timer.Elapsed += new MyClass((sender, e)=> { /* do stuff */});

如何以通用方式定义MyClass

我可以让Myclass 继承自ElapsedEventHandler,但它只能用于此事件。我正在考虑让MyClassAction<object, EventArg> 固有,因为你也可以写

timer.Elapsed += (sender, e) => { /* do stuff */ }

但我没有让那个工作。有什么建议吗?

【问题讨论】:

    标签: c# lambda delegates action


    【解决方案1】:

    您无法创建将成为委托的类,但您可以从您的类创建委托。

    考虑一个类:

    public class MyClass 
    {
        public void OnTimerElapsed(object sender, EventArgs e)
        {
        }
    }
    

    现在你将你的类方法连接到事件:

    var obj = new MyClass();
    timer.Elapsed += obj.OnTimerElapsed;
    

    你也可以断开它:

    timer.Elapsed -= obj.OnTimerElapsed;
    

    您应该阅读更多关于 C# 事件的信息,例如:https://msdn.microsoft.com/en-us/library/aa645739(v=vs.71).aspx

    【讨论】:

    • 很好的解决方法。委托A 不能转换为委托B - 但是只要它们的签名兼容,方法组就可以转换为委托A 或委托B。 +1
    • 嗯,这不是一个变通方法,这是应该做的:)
    【解决方案2】:

    你不能 - 在 C# 的类型系统中,两个委托之间没有关系,即使他们的签名匹配。

    例如,Func<T, bool>Predicate<T> 是不相关的。


    此外,您假设表达式 (sender, e) => { /* do stuff */} 的类型为 Action<object, EventArg> 是错误的。 Lambda 表达式没有类型,本身。它们被转换为委托,具体取决于上下文。

    这就是为什么您不能将 lambda 表达式分配给 var - 因为无法推断类型 - 因为没有类型。

    var del = (int i) => i + 1;         //incorrect
    Func<int, int> del = i => i + 1;    //correct
    CustomDelegate del = i => i + 1;    //correct
    
    
    delegate int CustomDelegate(int i);
    

    【讨论】:

      【解决方案3】:

      好的。这很棘手。但我不得不说.. 通过使用隐式转换的美妙世界是可能的。尝试这样开始..

      // define a new class called EventCall
      public class EventCall<T> {
          // this one will be returned to be executed directly after your initialization
          public T Handler { get; private set; }
      
          public EventCall(T handler) {
              if (handler == null) throw new ArgumentNullException("handler");
              this.Handler = handler;
              // the intercept code can be inserted here..
              // but i can't see any point of doing this..
          }
      
          // this method will return the handler directly after the initialization
          public static implicit operator T(EventCall<T> c) {
              return this.Handler;
          }
      }
      
      // now you can use it like
      timer.Elapsed += new EventCall<ElapsedEventHandler>((sender, args) => { /* code to invoke */ });
      

      这个有效。我刚刚自己测试过。但是类型参数T 始终需要匹配正确的事件处理程序类型..

      这段代码所做的基本上是使用T 参数来获取直接传递给构造函数然后(通过隐式转换)立即返回的新对象的类型。这有点矫枉过正..但无论如何。希望对您有所帮助..

      【讨论】:

      • 隐式运算符打开了一些新的视角。但我还没到。我想在事件触发时拦截代码,但使用创建拦截器时收集的一些数据。我已经设法从其他答案中获得了一些见解。我希望这个答案所有部分都可以汇集在一起​​。
      • 好的。你能提供更多信息吗?也许我只是愚蠢,但我无法弄清楚你的确切需求..
      • 好吧,如果我在你写的地方插入代码 // 拦截代码可以在这里插入.. // 但我看不出这样做有什么意义.. 它会在 EventCall 执行时执行建。当事件触发时,它仍然像你得到它一样执行处理程序。正是在这一点上,我想做更多的事情。所以,我想做的更像是:return (sender, e) => { DoStuff(); this.Handler(sender, e); }
      • 我很抱歉地说,但我回答的方式根本不可能。当事件被触发以及使用了哪些参数时,有一些邪恶的事件钩子方法可以窥探到它......
      • 我不喜欢邪恶的钩子,所以我来豌豆“它做不到”。虽然我也不喜欢“做不到”。
      猜你喜欢
      • 1970-01-01
      • 2011-03-30
      • 2017-05-14
      • 2020-02-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-14
      • 2018-07-08
      相关资源
      最近更新 更多