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

    <small id='96Kkd'></small><noframes id='96Kkd'>

    1. <tfoot id='96Kkd'></tfoot>
        <bdo id='96Kkd'></bdo><ul id='96Kkd'></ul>

        在 C# 中,为什么我不能传递另一个类的 EventHandler 引用,我该如何绕过它?

        时间:2023-09-16
      1. <i id='w5OcI'><tr id='w5OcI'><dt id='w5OcI'><q id='w5OcI'><span id='w5OcI'><b id='w5OcI'><form id='w5OcI'><ins id='w5OcI'></ins><ul id='w5OcI'></ul><sub id='w5OcI'></sub></form><legend id='w5OcI'></legend><bdo id='w5OcI'><pre id='w5OcI'><center id='w5OcI'></center></pre></bdo></b><th id='w5OcI'></th></span></q></dt></tr></i><div id='w5OcI'><tfoot id='w5OcI'></tfoot><dl id='w5OcI'><fieldset id='w5OcI'></fieldset></dl></div>

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

          • <tfoot id='w5OcI'></tfoot>

            • <legend id='w5OcI'><style id='w5OcI'><dir id='w5OcI'><q id='w5OcI'></q></dir></style></legend>
                  <bdo id='w5OcI'></bdo><ul id='w5OcI'></ul>
                    <tbody id='w5OcI'></tbody>

                • 本文介绍了在 C# 中,为什么我不能传递另一个类的 EventHandler 引用,我该如何绕过它?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着跟版网的小编来一起学习吧!

                  问题描述

                  如果我有具有公共事件 SomeEvent 的 ClassA 和具有接受 EventHandler 引用的方法 addListener 的 ClassC,为什么 ClassB 不能有一行显示 c.addListener(ref a.SomeEvent)?如果我尝试我得到一个编译器错误,上面写着:事件 'ClassA.SomeEvent' 只能出现在 += 或 -= 的左侧(除非在类型 'ClassA' 中使用).

                  If I have ClassA that has a public event, SomeEvent, and ClassC that has method, addListener, that accepts an EventHandler reference, why can't ClassB have a line that says c.addListener(ref a.SomeEvent)? If I try I get a compiler error that says: "The event 'ClassA.SomeEvent' can only appear on the left hand side of += or -= (except when used from within the type 'ClassA').

                  为什么会有这个限制?我怎样才能绕过它,同时保持合理地靠近我的结构?

                  Why does this restriction exist? And how can I get around it while staying reasonably close to my structure?

                  我是 C# 新手;任何帮助,将不胜感激.谢谢!

                  I'm a C# newbie; any help would be appreciated. Thanks!

                  class ClassA {
                      public event EventHandler SomeEvent;
                  }
                  
                  ClassB{
                      public ClassB() {
                  
                          ClassA a = new ClassA();
                          ClassC c = new ClassC();
                          c.addListener(ref a.SomeEvent);  //Compile error
                      }
                  }
                  
                  class ClassC {
                      public void addListener(ref EventHandler handler) {
                          handler += onEvent;
                      }
                  
                      private void onEvent(object sender, EventArgs e) {
                          //do stuff
                      }
                  
                  }
                  

                  推荐答案

                  event 关键字为私有委托对象创建访问器.与属性完全相同的事情,它限制对私有字段的访问.当您使用属性而不是事件时,您的代码片段会失败并出现类似的错误:

                  The event keyword creates an accessor for a private delegate object. The exact same thing a property does, it restricts access to a private field. Your code snippet fails with a similar kind of error when you use a property instead of an event:

                    class ClassA {
                      public int Property { get; set; }
                    }
                    class ClassB {
                      public ClassB() {
                        ClassA a = new ClassA();
                        ClassC c = new ClassC();
                        c.setValue(ref a.Property);   // CS0206
                      }
                    }
                    class ClassC {
                      public void setValue(ref int value) {
                        value = 42;
                      }
                    }
                  

                  现在更容易看到,编译器无法确保 setValue() 方法使用属性设置器.它也不知道value"参数是一个带有 setter 或普通字段的属性.

                  It is easier to see now, there is no way for the compiler to ensure that the setValue() method uses the property setter. Nor could it know that the "value" argument is a property with a setter or a plain field.

                  事件不太清楚,因为有太多的语法糖在起作用.本声明

                  It is less clear for an event because there is so much syntax sugar at work. This declaration

                  public event EventHandler SomeEvent;
                  

                  实际生成这段代码:

                  private EventHandler _SomeEvent;
                  public event SomeEvent {
                    add    { _SomeEvent += new EventHandler(value); }
                    remove { _SomeEvent -= new EventHandler(value); }
                  }
                  

                  add 和 remove 访问器等效于属性的 get 和 set 访问器,它们防止代码与私有 _SomeEvent 字段混淆.按照惯例,使用 += 时调用 add 访问器,使用 -= 调用 remove.将此与我之前为属性给出的示例进行比较.同样的问题,您不能使用 ref 关键字,并且 ClassC.addListener() 将无法知道处理程序实际上是一个事件而不是委托对象.如果编译器改为传递 _SomeEvent,那么使用访问器的意义就丢失了.

                  The add and remove accessors are equivalent to the get and set accessors of a property, they prevent code from messing with the private _SomeEvent field. By convention, the add accessor is invoked when you use +=, remove is invoked with -=. Compare this with the earlier example I gave for a property. Same problem, you can't use the ref keyword and ClassC.addListener() would have no way to know that the handler is actually an event instead of a delegate object. If the compiler would pass _SomeEvent instead, the point of using the accessors is lost.

                  你可以重构代码来解决这个问题:

                  You can restructure the code to solve this problem:

                    class ClassC {
                      public EventHandler getListener() {
                        return new EventHandler(onEvent);
                      }
                      private void onEvent(object sender, EventArgs e) { }
                    }
                  ...
                        a.SomeEvent += c.getListener();
                  

                  <小时>

                  最后一点:事件和属性之间的对称性有点丢失,如果您没有明确编写它们,C# 编译器会自动生成添加/删除访问器.它不会为属性执行此操作.它会使自动属性变得容易得多:


                  One final note: the symmetry between an event and a property is a bit lost, the C# compiler automatically generates the add/remove accessors if you don't write them explicitly. It doesn't do this for a property. It would have made automatic properties a lot easier:

                  property int Property;
                  

                  但这需要在语言中添加一个新关键字,这是 C# 团队非常不喜欢的.VB.NET 和 C++/CLI 等其他语言确实有这个关键字.

                  But that would have required adding a new keyword to the language, something the C# team really dislikes. Other languages like VB.NET and C++/CLI do have that keyword.

                  这篇关于在 C# 中,为什么我不能传递另一个类的 EventHandler 引用,我该如何绕过它?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

                  上一篇:如何在运行时克隆 Control 事件处理程序? 下一篇:如何使用反射将事件处理程序附加到事件?

                  相关文章

                  1. <tfoot id='icWsp'></tfoot>
                    <legend id='icWsp'><style id='icWsp'><dir id='icWsp'><q id='icWsp'></q></dir></style></legend>
                  2. <i id='icWsp'><tr id='icWsp'><dt id='icWsp'><q id='icWsp'><span id='icWsp'><b id='icWsp'><form id='icWsp'><ins id='icWsp'></ins><ul id='icWsp'></ul><sub id='icWsp'></sub></form><legend id='icWsp'></legend><bdo id='icWsp'><pre id='icWsp'><center id='icWsp'></center></pre></bdo></b><th id='icWsp'></th></span></q></dt></tr></i><div id='icWsp'><tfoot id='icWsp'></tfoot><dl id='icWsp'><fieldset id='icWsp'></fieldset></dl></div>

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

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