【问题标题】:How to handle event across chain of objects?如何跨对象链处理事件?
【发布时间】:2012-09-03 07:54:06
【问题描述】:

如果有以下情况:

public static void main() { 
    MyClass1 obj = new MyClass1();
    obj.Method1();
}
public class MyClass1() {
    public void Method1() {
        MyClass2 obj = new MyClass2();
        obj.Method1();
    }
}
public class MyClass2() {
   public void Method1() {
       MyClass3 obj = new MyClass3();
       obj.Method1();
   }
}
public class MyClass3() {
   public void Method1() {
       // Raise event here that is handled in MyClass1?    
   }
}

MyClass3.Method1() 能否引发在MyClass1 中处理的事件?

如果我想实现这一点,如何编写事件处理代码?

【问题讨论】:

    标签: c# .net events event-handling


    【解决方案1】:

    是的,它可以,但由于每个级别都不知道您链的更深层次,因此您必须在每个类上创建事件。有些是这样的:

    public static void main() { 
        MyClass1 obj = new MyClass1();
        obj.MyEvent += (s, e) => { Console.WriteLine("Fired!"); };
        obj.Method1();
    }
    
    public class MyClass1 {
        public void Method1() {
            MyClass2 obj = new MyClass2();
            obj.MyEvent += (s, e) => { OnMyEvent(); };
            obj.Method1();
        }
        public event EventHandler MyEvent;
        private void OnMyEvent() {
            var myEvent = MyEvent;
            if (myEvent != null)
                myEvent(this, EventArgs.Empty);
        }
    }
    public class MyClass2 {
        public void Method1() {
            MyClass3 obj = new MyClass3();
            obj.MyEvent += (s, e) => { OnMyEvent(); };
            obj.Method1();
        }
        public event EventHandler MyEvent;
        private void OnMyEvent() {
            var myEvent = MyEvent;
            if (myEvent != null)
                myEvent(this, EventArgs.Empty);
        }
    }
    public class MyClass3 {
        public void Method1() {
            // Raise event here that is handled in MyClass1?    
            OnMyEvent();
        }
        public event EventHandler MyEvent;
        private void OnMyEvent() {
            var myEvent = MyEvent;
            if (myEvent != null)
                myEvent(this, EventArgs.Empty);
        }
    }
    

    【讨论】:

    • 所以你必须将事件链接回 MyClass1,所以实际上 MyClass1 无法处理 MyClass3 引发的事件?
    • 您的问题是 MyClass1 不知道将引发事件的 MyClass3 的实例,因此它无法订阅该事件。
    • @PaulLassiter - Francesco 打败了我。
    • 使用添加/删除语法更容易。
    • @ChrisGessler:你同意Philipp's answercallback 类型的解决方案会更好吗?
    【解决方案2】:

    要链接事件处理程序,请使用 MyClass2 中的添加/删除语法。在 MyClass1 中设置 SomeEvent 并在 MyClass3 中引发它。

    public class MyClass1             
    {             
        MyClass2 obj = new MyClass2(); 
    
        public MyClass1()
        {
            obj.SomeEvent += obj_SomeEvent;
        }
    
        public void Method1()             
        {                      
            obj.Method1();             
        }             
    
        private static void obj_SomeEvent(object sender, EventArgs e)             
        {             
            Console.WriteLine("Some event fired");             
        }             
    }  
    
    
    public class MyClass2() 
    {    
       MyClass3 cls3 = new MyClass3();
    
       public void Method1() 
       {     
           cls3.FireSomeEvent();    
       }   
    
        public event MyEventHandler SomeEvent
        { 
            add { this.cls3.SomeEvent += value; } 
            remove { this.cls3.SomeEvent -= value; } 
        }  
    }
    
    public class MyClass3() 
    {
        public event EventHandler SomeEvent;
    
        private void OnSomeEvent() 
        { 
            if (SomeEvent!= null) 
            { 
                SomeEvent(this, new EventArgs()); 
            } 
        } 
    
        public void FireSomeEvent
        {
            OnSomeEvent();
        }
    }
    

    【讨论】:

    • 在这里,您以某种方式“作弊”将局部变量转换为字段(MyClass2 中的 MyClass3)。此外,它不起作用,因为当您订阅 MyClass2 的 SomeEvent 时,cls3 为空。这意味着您应该在 MyClass2 的 Method1 之外实例化 MyClass3,但我认为这不是 OP 可能喜欢的。
    【解决方案3】:

    事件处理 ABC 假设您有订阅者和发布者。所以你可能希望你的 MyClass3 有公共事件,而 MyClass1 订阅这个事件。

    但是在您的特定代码中,这种复杂性没有任何意义 - 使用回调函数的最简单方法:

    public static void main() { 
        MyClass1 obj = new MyClass1();
        obj.Method1();
    }
    public class MyClass1{
        public void Method1() {
            MyClass2 obj = new MyClass2();
            obj.Method1(MyEventHandler);
        }
    
        public void MyEventHandler() {
        //...
        }
    
    }
    public class MyClass2{
       public void Method1(Action callback) {
           MyClass3 obj = new MyClass3();
           obj.Method1(callback);
       }
    }
    public class MyClass3{
       public void Method1(Action callback) {
           // Raise event here that is handled in MyClass1?    
           callback();
       }
    }
    

    【讨论】:

    • Action 类型是新的吗?我只使用 C# 2.0 。可以改用delegate 吗?
    • @PaulLassiter Action 只是一个没有参数和 void 返回类型的委托。你可以自己定义一些等价的东西。
    • 公共委托 void Action();
    【解决方案4】:

    您可以将事件添加到中间类以将事物连接起来。像这样的:

    using System;
    using System.Windows.Forms;
    
    namespace Demo
    {
        class Program
        {
            static void Main(string[] args)
            {
                MyClass1 obj = new MyClass1();
                obj.Method1();
            }
        }
    
        public class MyClass1
        {
            public void Method1()
            {
                MyClass2 obj = new MyClass2();
                obj.SomethingHappened += somethingHappened;
                obj.Method1();
            }
    
            private static void somethingHappened(object sender, EventArgs e)
            {
                Console.WriteLine("Something happened!");
            }
        }
    
        public class MyClass2
        {
            public void Method1()
            {
                MyClass3 obj = new MyClass3();
                obj.SomethingHappened += onSomethingHappened;
                obj.Method1();
            }
    
            public event EventHandler SomethingHappened;
    
            private void onSomethingHappened(object sender, EventArgs e)
            {
                var handler = SomethingHappened;
    
                if (handler != null)
                {
                    handler(this, e);
                }
            }
        }
    
        public class MyClass3
        {
            public void Method1()
            {
                onSomethingHappened();
            }
    
            private void onSomethingHappened()
            {
                var handler = SomethingHappened;
    
                if (handler != null)
                {
                    handler(this, new EventArgs());
                }
            }
    
            public event EventHandler SomethingHappened;
        }
    }
    

    您可能需要考虑的一件事是在中间类中使用“sender”参数做什么。您可以将其设为 MyClass2(如上面的代码中所示),或者您可以像这样保留原始发件人:

    private void onSomethingHappened(object sender, EventArgs e)
    {
        var handler = SomethingHappened;
    
        if (handler != null)
        {
            handler(sender, e);
        }
    }
    

    【讨论】:

      【解决方案5】:

      如果你想避免回调解决方案和每个类中的事件链,你基本上有2个解决方案。

      第一个包括将 MyClassX 类型的局部变量转换为字段,即像 Chris Gessler 建议的那样,但完全遵循这种方法并删除局部变量。

      public static void main() { 
          MyClass1 obj = new MyClass1();
          obj.c2.c3.SomeEvent += obj_SomeEvent;      
          obj.Method1();
      }
      
      private static void obj_SomeEvent(object sender, EventArgs e)             
      {             
          Console.WriteLine("Some event fired");             
      }
      
      public class MyClass1() {
          public MyClass2 c2 = new MyClass2();
      
          public void Method1() {
              c2.Method1();
          }
      }
      public class MyClass2() {
         public MyClass3 c3 = new MyClass3();
      
         public void Method1() {
             c3.Method1();
         }
      }
      public class MyClass3() {
          public event EventHandler SomeEvent;
      
          private void OnSomeEvent() 
          { 
              if (SomeEvent!= null) 
              { 
                  SomeEvent(this, new EventArgs()); 
              } 
          } 
         public void Method1() {
             OnSomeEvent();    
         }
      }
      

      您的另一个选择(但如果可行,这实际上取决于您尝试做什么,而且我不喜欢)是简单地将 MyClass3 中的事件定义为静态:

      public static void main() { 
          MyClass3.SomeEvent += obj_SomeEvent;
          MyClass1 obj = new MyClass1();
          obj.Method1();
      }
      
      private static void obj_SomeEvent(object sender, EventArgs e)             
      {             
           Console.WriteLine("Some event fired");             
      }
      
      public class MyClass1() {
          public void Method1() {
              MyClass2 obj = new MyClass2();
              obj.Method1();
          }
      }
      public class MyClass2() {
         public void Method1() {
             MyClass3 obj = new MyClass3();
             obj.Method1();
         }
      }
      public class MyClass3() {
          public static event EventHandler SomeEvent;
      
          private void OnSomeEvent(MyClass3 anObj) 
          { 
              if (SomeEvent!= null) 
              { 
                  SomeEvent(anObj, new EventArgs()); 
              } 
          }
      
          public void Method1() {
             OnSomeEvent(this);    
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-01-13
        • 2011-10-10
        • 2012-12-10
        • 2017-03-18
        • 1970-01-01
        相关资源
        最近更新 更多