我使用的是dot net标准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);
}
}
但给我一个错误:
错误事件"ICrawler.NextPage"只能出现在左侧+=或-=侧
我开始了这次培训,那么问题出在哪里呢?
原因
一个类中以;
结尾的简单事件定义由两部分组成,即只包含添加/删除访问器(方法(的事件和处理程序委托。
对于
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;
}
请注意,无论事件定义的访问修饰符是什么,backing字段始终为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);