• <small id='7OV8g'></small><noframes id='7OV8g'>

  • <tfoot id='7OV8g'></tfoot>

  • <i id='7OV8g'><tr id='7OV8g'><dt id='7OV8g'><q id='7OV8g'><span id='7OV8g'><b id='7OV8g'><form id='7OV8g'><ins id='7OV8g'></ins><ul id='7OV8g'></ul><sub id='7OV8g'></sub></form><legend id='7OV8g'></legend><bdo id='7OV8g'><pre id='7OV8g'><center id='7OV8g'></center></pre></bdo></b><th id='7OV8g'></th></span></q></dt></tr></i><div id='7OV8g'><tfoot id='7OV8g'></tfoot><dl id='7OV8g'><fieldset id='7OV8g'></fieldset></dl></div>
    <legend id='7OV8g'><style id='7OV8g'><dir id='7OV8g'><q id='7OV8g'></q></dir></style></legend>

      <bdo id='7OV8g'></bdo><ul id='7OV8g'></ul>

      1. C# 事件如何在幕后工作?

        时间:2023-11-11

          <tfoot id='dMK7y'></tfoot>

          <legend id='dMK7y'><style id='dMK7y'><dir id='dMK7y'><q id='dMK7y'></q></dir></style></legend>

          • <bdo id='dMK7y'></bdo><ul id='dMK7y'></ul>
          • <i id='dMK7y'><tr id='dMK7y'><dt id='dMK7y'><q id='dMK7y'><span id='dMK7y'><b id='dMK7y'><form id='dMK7y'><ins id='dMK7y'></ins><ul id='dMK7y'></ul><sub id='dMK7y'></sub></form><legend id='dMK7y'></legend><bdo id='dMK7y'><pre id='dMK7y'><center id='dMK7y'></center></pre></bdo></b><th id='dMK7y'></th></span></q></dt></tr></i><div id='dMK7y'><tfoot id='dMK7y'></tfoot><dl id='dMK7y'><fieldset id='dMK7y'></fieldset></dl></div>
              <tbody id='dMK7y'></tbody>

                  <small id='dMK7y'></small><noframes id='dMK7y'>

                1. 本文介绍了C# 事件如何在幕后工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着跟版网的小编来一起学习吧!

                  问题描述

                  我正在使用 C#、.NET 3.5.我了解如何利用事件,如何在我的班级中声明它们,如何从其他地方挂钩它们等等.一个人为的例子:

                  I'm using C#, .NET 3.5. I understand how to utilize events, how to declare them in my class, how to hook them from somewhere else, etc. A contrived example:

                  public class MyList
                  {
                      private List<string> m_Strings = new List<string>();
                      public EventHandler<EventArgs> ElementAddedEvent;
                  
                      public void Add(string value)
                      {
                          m_Strings.Add(value);
                          if (ElementAddedEvent != null)
                              ElementAddedEvent(value, EventArgs.Empty);
                      }
                  }
                  
                  [TestClass]
                  public class TestMyList
                  {
                      private bool m_Fired = false;
                  
                      [TestMethod]
                      public void TestEvents()
                      {
                          MyList tmp = new MyList();
                          tmp.ElementAddedEvent += new EventHandler<EventArgs>(Fired);
                          tmp.Add("test");
                          Assert.IsTrue(m_Fired);
                      }
                  
                      private void Fired(object sender, EventArgs args)
                      {
                          m_Fired = true;
                      }
                  }
                  

                  然而,我理解的是,当一个人声明一个事件处理程序时

                  However, what I do not understand, is when one declares an event handler

                  public EventHandler<EventArgs> ElementAddedEvent;
                  

                  它从未被初始化 - 那么,ElementAddedEvent 究竟是什么?它指向什么?以下将不起作用,因为 EventHandler 从未初始化:

                  It's never initialized - so what, exactly, is ElementAddedEvent? What does it point to? The following won't work, because the EventHandler is never initialized:

                  [TestClass]
                  public class TestMyList
                  {
                      private bool m_Fired = false;
                  
                      [TestMethod]
                      public void TestEvents()
                      {
                          EventHandler<EventArgs> somethingHappend;
                          somethingHappend += new EventHandler<EventArgs>(Fired);
                          somethingHappend(this, EventArgs.Empty);
                          Assert.IsTrue(m_Fired);
                      }
                  
                      private void Fired(object sender, EventArgs args)
                      {
                          m_Fired = true;
                      }
                  }
                  

                  我注意到有一个 EventHandler.CreateDelegate(...),但所有方法签名都表明这仅用于通过典型的 ElementAddedEvent += new EventHandler(MyMethod) 将 Delegates 附加到已经存在的 EventHandler.

                  I notice that there is an EventHandler.CreateDelegate(...), but all the method signatures suggest this is only used for attaching Delegates to an already existing EventHandler through the typical ElementAddedEvent += new EventHandler(MyMethod).

                  我不确定我正在尝试做的什么是否会有所帮助......但最终我想在 LINQ 中提出一个抽象的父 DataContext,它的孩子可以注册哪些表类型他们想要观察",所以我可以有诸如更新前和更新后之类的事件,但特定于类型.像这样的:

                  I'm not sure if what I am trying to do will help... but ultimately I'd like to come up with an abstract parent DataContext in LINQ whose children can register which table Types they want "observed" so I can have events such as BeforeUpdate and AfterUpdate, but specific to types. Something like this:

                  public class BaseDataContext : DataContext
                  {
                      private static Dictionary<Type, Dictionary<ChangeAction, EventHandler>> m_ObservedTypes = new Dictionary<Type, Dictionary<ChangeAction, EventHandler>>();
                  
                      public static void Observe(Type type)
                      {
                          if (m_ObservedTypes.ContainsKey(type) == false)
                          {
                              m_ObservedTypes.Add(type, new Dictionary<ChangeAction, EventHandler>());
                  
                              EventHandler eventHandler = EventHandler.CreateDelegate(typeof(EventHandler), null, null) as EventHandler;
                              m_ObservedTypes[type].Add(ChangeAction.Insert, eventHandler);
                  
                              eventHandler = EventHandler.CreateDelegate(typeof(EventHandler), null, null) as EventHandler;
                              m_ObservedTypes[type].Add(ChangeAction.Update, eventHandler);
                  
                              eventHandler = EventHandler.CreateDelegate(typeof(EventHandler), null, null) as EventHandler;
                              m_ObservedTypes[type].Add(ChangeAction.Delete, eventHandler);
                          }
                      }
                  
                      public static Dictionary<Type, Dictionary<ChangeAction, EventHandler>> Events
                      {
                          get { return m_ObservedTypes; }
                      }
                  }
                  
                  
                  public class MyClass
                  {
                      public MyClass()
                      {
                          BaseDataContext.Events[typeof(User)][ChangeAction.Update] += new EventHandler(OnUserUpdate);
                      }
                  
                      public void OnUserUpdated(object sender, EventArgs args)
                      {
                          // do something
                      }
                  }
                  

                  考虑到这一点让我意识到我并不真正了解事件背后发生的事情 - 我想了解:)

                  Thinking about this made me realize I don't really understand what's happening under the hod with events - and I would like to understand :)

                  推荐答案

                  我已经在 一篇文章,但这里是摘要,假设您对 代表 自己:

                  I've written this up in a fair amount of detail in an article, but here's the summary, assuming you're reasonably happy with delegates themselves:

                  • 事件只是添加"方法和删除"方法,就像属性实际上只是获取"方法和设置"方法一样.(事实上,CLI 也允许使用raise/fire"方法,但 C# 从不生成此方法.)元数据通过对方法的引用来描述事件.
                  • 当您声明一个类字段事件(就像您的 ElementAddedEvent)编译器生成方法和一个私有字段(与委托的类型相同).在类中,当您引用 ElementAddedEvent 时,您指的是该字段.在课堂之外,您指的是该领域.
                  • 当任何人(使用 += 运算符)订阅调用 add 方法的事件时.当他们取消订阅(使用 -= 运算符)调用删除时.
                  • 对于类似字段的事件,有一些同步,否则添加/删除只需调用 Delegate.合并/删除以更改自动生成字段的值.这两个操作都分配给支持字段 - 请记住,委托是不可变的.换句话说,自动生成的代码很像这样:

                  • An event is just an "add" method and a "remove" method, in the same way that a property is really just a "get" method and a "set" method. (In fact, the CLI allows a "raise/fire" method as well, but C# never generates this.) Metadata describes the event with references to the methods.
                  • When you declare a field-like event (like your ElementAddedEvent) the compiler generates the methods and a private field (of the same type as the delegate). Within the class, when you refer to ElementAddedEvent you're referring to the field. Outside the class, you're referring to the field.
                  • When anyone subscribes to an event (with the += operator) that calls the add method. When they unsubscribe (with the -= operator) that calls the remove.
                  • For field-like events, there's some synchronization but otherwise the add/remove just call Delegate.Combine/Remove to change the value of the auto-generated field. Both of these operations assign to the backing field - remember that delegates are immutable. In other words, the autogenerated code is very much like this:

                  // Backing field
                  // The underscores just make it simpler to see what's going on here.
                  // In the rest of your source code for this class, if you refer to
                  // ElementAddedEvent, you're really referring to this field.
                  private EventHandler<EventArgs> __ElementAddedEvent;
                  
                  // Actual event
                  public EventHandler<EventArgs> ElementAddedEvent
                  {
                      add
                      {
                          lock(this)
                          {
                              // Equivalent to __ElementAddedEvent += value;
                              __ElementAddedEvent = Delegate.Combine(__ElementAddedEvent, value);
                          }
                      }
                      remove
                      {
                          lock(this)
                          {
                              // Equivalent to __ElementAddedEvent -= value;
                              __ElementAddedEvent = Delegate.Remove(__ElementAddedEvent, value);
                          }
                      }
                  }
                  

                2. 在您的情况下,生成字段的初始值为 null - 如果删除所有订阅者,它将始终再次变为 null,因为那是Delegate.Remove 的行为.

                3. The initial value of the generated field in your case is null - and it will always become null again if all subscribers are removed, as that is the behaviour of Delegate.Remove.

                  如果你想要一个no-op"处理程序来订阅你的事件,以避免无效性检查,你可以这样做:

                  If you want a "no-op" handler to subscribe to your event, so as to avoid the nullity check, you can do:

                  public EventHandler<EventArgs> ElementAddedEvent = delegate {};
                  

                  delegate {} 只是一个匿名方法,它不关心它的参数并且什么都不做.

                  The delegate {} is just an anonymous method which doesn't care about its parameters and does nothing.

                  如果还有什么不清楚的地方,请询问,我会尽力帮助的!

                  If there's anything that's still unclear, please ask and I'll try to help!

                  这篇关于C# 事件如何在幕后工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

                4. 上一篇:代表:谓词 vs. 动作 vs. Func 下一篇:EndInvoke() 是可选的,是可选的,还是绝对不是可选的?

                  相关文章

                  <tfoot id='yd3JO'></tfoot>
                  1. <legend id='yd3JO'><style id='yd3JO'><dir id='yd3JO'><q id='yd3JO'></q></dir></style></legend>

                    <small id='yd3JO'></small><noframes id='yd3JO'>

                    • <bdo id='yd3JO'></bdo><ul id='yd3JO'></ul>

                      <i id='yd3JO'><tr id='yd3JO'><dt id='yd3JO'><q id='yd3JO'><span id='yd3JO'><b id='yd3JO'><form id='yd3JO'><ins id='yd3JO'></ins><ul id='yd3JO'></ul><sub id='yd3JO'></sub></form><legend id='yd3JO'></legend><bdo id='yd3JO'><pre id='yd3JO'><center id='yd3JO'></center></pre></bdo></b><th id='yd3JO'></th></span></q></dt></tr></i><div id='yd3JO'><tfoot id='yd3JO'></tfoot><dl id='yd3JO'><fieldset id='yd3JO'></fieldset></dl></div>