在C#中为什么不能我通过其他类的事件处理程序的参考,我怎么能围绕它得到什么? [英] In C# why can't I pass another class' EventHandler reference and how can I get around it?

查看:143
本文介绍了在C#中为什么不能我通过其他类的事件处理程序的参考,我怎么能围绕它得到什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我有ClassA的,有一个公共事件,SomeEvent和ClassC有方法的addListener,接受一个事件处理程序的参考,为什么不能ClassB的有这样一行c.addListener(REF a.SomeEvent)?如果我试试我得到一个说:编译错误:该事件'ClassA.SomeEvent只能出现在左手侧+ =或 - =(从类型ClassA的'内使用时除外)



为什么这个限制存在?又如何,我可以避开它,同时保持合理的接近我的结构?



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

 类ClassA的{
公共事件的EventHandler SomeEvent;
}

ClassB的{
公共ClassB的(){

ClassA的一个=新ClassA的();
ClassC C =新ClassC();
c.addListener(REF a.SomeEvent); //编译错误
}
}

类ClassC {
公共无效的addListener(REF事件处理程序处理程序){
+处理器=的onEvent;
}

私人无效的onEvent(对象发件人,EventArgs五){
//做的东西
}

}


解决方案

本次活动的关键字创建对于私人委托对象的访问。属性不完全一样的东西,它限制进入私人领域。您的代码段失败,出现类似错误的类型,当你使用一个属性,而不是一个事件:

 类ClassA的{
酒店的公共int属性{搞定;组; }
}
级ClassB的{
公共ClassB的(){
ClassA的一个=新ClassA的();
ClassC C =新ClassC();
c.setValue(REF a.Property); // CS0206
}
}
类ClassC {
公共无效的setValue(REF int值){
值= 42;
}
}



这是比较容易看到现在,也没办法编译器,以确保setValue()方法使用属性setter。它也可以知道,价值的说法是一个二传手或纯场的属性。



这是一个事件不太清楚,因为有这么多的语法糖工作中。该声明

 公共事件的EventHandler SomeEvent; 



实际生成代码:

 私人事件处理_SomeEvent; 
公共事件SomeEvent {
加{_SomeEvent + =新的EventHandler(值); }
拆下{_SomeEvent - =新的EventHandler(值); }
}



添加和删除访问器相当于一个get和set访问财产,他们阻止代码与私人领域_SomeEvent搞乱。按照惯例,add访问当您使用+ =调用,取出被调用, - =。与前面的例子我给一个属性进行比较。同样的问题,您不能使用ref关键字和ClassC.addListener()将没有办法知道,处理器实际上是一个事件,而不是一个委托对象。如果编译器传递_SomeEvent相反,使用访问点丢失



您可以通过重构代码来解决这个问题:

 类ClassC {
公共事件处理getListener(){
返回新的EventHandler(的onEvent);
}
私人无效的onEvent(对象发件人,EventArgs五){}
}
...
a.SomeEvent + = c.getListener();






最后要注意的:事件之间的对称性和一个属性是有点失落,C#编译器自动生成的添加/删除访问,如果你不把它们明确写入。它不为一个属性做到这一点。它会作出自动属性轻松了许多:

 属性int属性; 



但是,这将需要添加一个新的关键字的语言,一些C#团队真的不喜欢。就像VB.NET和C ++ / CLI等语言的确有这个关键字。


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?

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
    }

}

解决方案

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;
    }
  }

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;

actually generates this code:

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

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();


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;

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#中为什么不能我通过其他类的事件处理程序的参考,我怎么能围绕它得到什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆