C#语言设计:事件的显式接口实现

con*_*low 32 c# events interface explicit-implementation

关于C#语言设计的小问题:))

如果我有这样的界面:

interface IFoo {
  int Value { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

可以使用C#3.0自动实现的属性显式实现此类接口:

sealed class Foo : IFoo {
  int IFoo.Value { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

但如果我在界面中有一个事件:

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

并尝试使用类似字段的事件显式实现它:

sealed class Foo : IFoo {
  event EventHandler IFoo.Event;
}
Run Code Online (Sandbox Code Playgroud)

我将得到以下编译器错误:

error CS0071: An explicit interface implementation of an event must use event accessor syntax

我认为类似字段的事件是自动实现属性的某种二元论.

所以我的问题是:这种限制的设计原因是什么?

Eri*_*ert 30

有趣的问题.我做了一些关于语言笔记档案的讨论,我发现这个决定是在1999年10月13日作出的,但是这些笔记没有给出决定的理由.

在我的头脑中,我没有看到任何理论或实际原因,为什么我们不能有类似字段显式实现的事件.我也没有看到任何我们特别需要的理由.这可能不得不是未知的奥秘之一.

  • 现在这就是我有时仍然访问SO的原因......人们还会在哪里采取"我不知道"的答案. (7认同)
  • 似乎原因可能是您永远不会提出这样的事件,除非明确实现的事件具有与明确实现的方法不同的可见性规则,如我的答案中所解释的...... (4认同)

小智 26

我想这可能与你不能从类的其他成员调用显式接口实现这一事实有关:

public interface I
{
    void DoIt();
}

public class C : I
{
    public C()
    {
        DoIt(); // error CS0103: The name 'DoIt' does not exist in the current context
    }

    void I.DoIt() { }
}
Run Code Online (Sandbox Code Playgroud)

请注意,您可以先通过向上转换到接口来调用该方法:((I)this).DoIt();.有点难看,但它的工作原理.

如果事件可以显示为ControlFlow(OP)建议,那么你将如何实际提出它们?考虑:

public interface I
{
    event EventHandler SomethingHappened;
}

public class C : I
{
    public void OnSomethingHappened()
    {
        // Same problem as above
        SomethingHappened(this, EventArgs.Empty);
    }

    event EventHandler I.SomethingHappened;
}
Run Code Online (Sandbox Code Playgroud)

在这里,您甚至无法通过向上转换到接口来引发事件,因为事件只能从实现类中引发.因此,对于明确实现的事件要求访问器语法似乎是完全合理的.


Sté*_*écy 21

显式实现在接口中声明的事件时,必须使用手动提供通常由编译器提供的添加和删除事件访问器.访问者代码可以将接口事件连接到类中的另一个事件或其自己的委托类型.

例如,这将触发错误CS0071:

public delegate void MyEvent(object sender);

interface ITest
{
    event MyEvent Clicked;
}

class Test : Itest
{
    event MyEvent ITest.Clicked;  // CS0071
    public static void Main() { }
}
Run Code Online (Sandbox Code Playgroud)

正确的方法是:

public delegate void MyEvent(object sender);

interface ITest
{
    event MyEvent Clicked;
}

class Test : Itest
{
    private MyEvent clicked;

    event MyEvent Itest.Clicked
    {
        add
        {
            clicked += value;
        }

        remove
        {
            clicked -= value;
        }
    }

    public static void Main() { }
}
Run Code Online (Sandbox Code Playgroud)

请参见编译器错误CS0071

  • +1也许不是这个问题的明确答案,但这只是为了节省我的时间,试图找出一个解决方案. (5认同)