Событие может появиться только в левой части += или -= dotnetstandard 2.1.

Я использую dot net standard 2.1 и С # 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);
    }
}

но возьмите ошибку:

Ошибка Событие ICrawler.NextPage может появляться только слева от += или -=

Я продолжил это обучение, так в чем проблема?

1 ответ

Решение

Причина

Простое определение события, заканчивающееся на ; в классе состоит из 2 частей: событие, которое содержит только средства доступа (методы) добавления / удаления, и делегат обработчика.

за

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() фактически обращается к делегату обработчика напрямую, а не к средствам доступа, и может быть выполнено только внутри самого класса.

Но простое определение события, заканчивающееся на ; в интерфейсе есть только абстрактное событие, которое содержит только абстрактные средства доступа добавления / удаления (абстрактные методы).

за

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);
Другие вопросы по тегам