为什么我们不能与访问者一起发起活动?

时间:2018-10-29 08:42:29

标签: c# events

我们为什么不能通过自定义实现引发事件,而没有它们则有可能吗?看到以下代码:

public class Program
{
    private EventHandler myEvent;
    public event EventHandler MyEvent
    {
        add { myEvent += value; }
        remove { myEvent -= value; }
    }

    public event EventHandler AnotherEvent;

    public static void Main()
    {
        var target = new Program();
        target.MyEvent(null, null);       // ERROR CS0079
        target.AnotherEvent(null, null);  // compiles
    }
}

您看到两个事件都在我的类中声明。尽管target.AnotherEvent(...)可以正常编译,但是target.MyEvent(...)不能:

  

事件MyEvent只能出现在+ =或-=的左侧。

我知道一个事件只是一个具有添加和删除方法的委托。因此AnotherEvent由编译器翻译为加法和减法:

private EventHandler _AnotherEvent;
public event EventHandler AnotherEvent
{ 
    add { _AnotherEvent += value; }
    remove { _AnotherEvent -= value; }
}

因此,我假设对AnotherEvent的调用已被编译器替换为对私有委托的调用,_AnotherEvent(...)

我说对了吗?是否有任何文档说明为什么第二个呼叫有效而前一个呼叫无效?或至少对此处的编译器有何描述?

4 个答案:

答案 0 :(得分:3)

使用自动事件时max_execution_time。编译器将为此创建一个字段(和一些方法),并在该字段上进行调用。因此public event EventHandler AnotherEvent;不再存在。是语法糖。

因此无法调用非自动事件。因为在编译后的代码中找不到它。它由public eventadd_方法代替。您只能在私有字段(生成的字段)上调用

这说明了为什么不能在类实例之外调用事件。

答案 1 :(得分:2)

它不起作用,因为现在只有一种方法可以获取实际的可调用事件处理程序。您已经注意到,只有null_resourceadd,而不是remove

事件处理程序的生成代码为:

get

它添加了两个方法引用,一个用于.event [mscorlib]System.EventHandler MyEvent { .addon instance void ConsoleApp1.Program::add_MyEvent(class [mscorlib]System.EventHandler) .removeon instance void ConsoleApp1.Program::remove_MyEvent(class [mscorlib]System.EventHandler) } // end of event Program::MyEvent ,一个用于add。如果您查看它,它将如何知道要调用的方法?如果removeadd比现在复杂得多怎么办?无法确定要调用哪个事件处理程序。

答案 2 :(得分:1)

它是语法糖。可以像后备字段一样调用AnotherEvent,这是编译器提供的一种便利(AnotherEvent是所谓的类似字段的事件)。添加自己的访问器后,事件声明将不再是类似于字段的事件,而必须通过其后备字段进行调用。

请参阅C# Language Specification的相关部分:

  

类似字段的事件

     

在包含事件声明的类或结构的程序文本中,某些事件可以像字段一样使用。成为   通过这种方式使用,事件不能是抽象的或外部的,并且必须   没有明确包含event_accessor_declarations。这样的事件可以   在允许使用字段的任何上下文中使用。该字段包含一个   委托(Delegates),它引用的事件处理程序列表   已添加到活动中。如果未添加事件处理程序,   该字段包含空值。

(重点是我的)

答案 3 :(得分:0)

建议您在添加或删除新的事件处理程序方法之前锁定事件。

说,看一下这段代码:

public event EventHandler MyEvent
{
    add
    {
        lock (objectLock)
        {
            myEvent += value;
        }
    }
    remove
    {
        lock (objectLock)
        {
            myEvent -= value;
        }
    }
}

public event EventHandler AnotherEvent;起作用的原因是当代码中未提供自定义事件访问器时,编译器将自动添加它们。

请遵循此文档How to: Implement Custom Event Accessors ,以获取有关正确实现的更多详细信息以及该post的其他来源。

关于实施:

 private EventHandler myEvent;
 public event EventHandler MyEvent
    {
        add
        {
            lock (objectLock)
            {
                myEvent += value;
            }
        }
        remove
        {
            lock (objectLock)
            {
                myEvent -= value;
            }
        }
    }

    public event EventHandler AnotherEvent;

    public static void Main()
    {
        var target = new Program();
        var myEvent =  target.MyEvent;
        myEvent?.Invoke(EventArgs.Empty, EventArgs.Empty);      
        target.AnotherEvent(null, null); 
    }

编辑以解释实现:

var myEvent =  target.MyEvent;

对于显式事件,您必须提供自己的后备存储-委托字段或类似EventHandlerList之类的东西,因此我们在这里只使用var