该事件只能出现在 += 或 -= dotnet standard 2.1 的左侧

The event can only appear on the left hand side of += or -= dotnetstandard 2.1

我正在使用 dot net standard 2.1 和 c# 8,我想为我的 class(接口)创建一个事件,我遵循 this tutorial 并编写了一个接口:

using System;
using Crawler.Paging;

namespace Crawler
{
    public interface ICrawler
    {
        public event EventHandler NextPage;
        protected virtual void OnNextPage(EventArgs e)
        {

            EventHandler handler = NextPage;
            handler?.Invoke(this,e);
        }
        void Paging(IPaging paging);
    }
}

但给我一个错误:

Error The event 'ICrawler.NextPage' can only appear on the left hand side of += or -=

我进行了这次培训,请问问题出在哪里?

原因

一个在class中以;结尾的简单事件定义由两部分组成,即事件,它只包含两个add/remove访问器(方法),以及处理程序委托。

class Foo
{
    public event EventHandler Bar;
}

等于

class Foo
{
    //The event
    public event EventHandler Bar
    {
        add => _bar += value;
        remove => _bar -= value;
    }

    //The handler value
    private EventHandler _bar;
}

请注意,无论事件定义的访问修饰符如何,支持字段始终为 private。所以 Bar?.Invoke() 实际上是直接访问处理程序委托,而不是访问器,并且只能在 class 本身内完成。

但是在接口中以;结尾的简单事件定义只是抽象事件,它只包含两个add/remove抽象访问器(抽象方法)。

interface IFoo
{
    event EventHandler Bar;
}

等于

interface IFoo
{
    public abstract EventHandler Bar;
    //The following syntax is invalid but shows how it works.
    /*
    event EventHandler Bar
    {
        abstract add;
        abstract remove;
    }
    */
}

C#中的默认接口实现特性并没有对其进行重大更改,因为接口不能包含任何字段(它定义了C#中的接口是什么)。只要处理程序委托不存在,就无法直接访问它,因此 Bar?.Invoke() 无效。

解决方案

有一个解决方法,使用手动实现的事件(这也是默认实现)和抽象 属性 作为处理程序委托:

interface IFoo
{
    protected EventHandler BarHandler { get; set; }

    event EventHandler Bar
    {
        add => BarHandler += value;
        remove => BarHandler -= value;
    }
}

class Foo : IFoo
{
    EventHandler IFoo.BarHandler { get; set; }
}

以便默认方法实现中的其他地方可以调用事件:

var handler = BarHandler;
handler?.Invoke(this, e);