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

arm*_*man 1 .net c#-8.0 .net-standard-2.1

我正在使用 dot net standard 2.1 和 c# 8,我想为我的类(接口)创建一个事件,我按照本教程 编写了一个接口:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

但请告诉我一个错误:

错误事件“ICrawler.NextPage”只能出现在+=或-=的左侧

我继续进行了这个训练,那么问题出在哪里呢?

Als*_*ein 5

原因

以类结尾的简单事件定义;由两部分组成,即事件(仅包含添加/删除访问器(方法))和处理程序委托。

为了

class Foo
{
    public event EventHandler Bar;
}
Run Code Online (Sandbox Code Playgroud)

等于

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

    //The handler value
    private EventHandler _bar;
}
Run Code Online (Sandbox Code Playgroud)

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

但是以接口结尾的简单事件定义;只是抽象事件,它只包含添加/删除抽象访问器(抽象方法)。

为了

interface IFoo
{
    event EventHandler Bar;
}
Run Code Online (Sandbox Code Playgroud)

等于

interface IFoo
{
    public abstract EventHandler Bar;
    //The following syntax is invalid but shows how it works.
    /*
    event EventHandler Bar
    {
        abstract add;
        abstract remove;
    }
    */
}
Run Code Online (Sandbox Code Playgroud)

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; }
}
Run Code Online (Sandbox Code Playgroud)

这样默认方法实现中的其他地方就可以调用该事件:

var handler = BarHandler;
handler?.Invoke(this, e);
Run Code Online (Sandbox Code Playgroud)