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

发布于 2024-08-22 08:35:40 字数 602 浏览 9 评论 0原文

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

如果我有一个这样的接口:

interface IFoo {
  int Value { get; set; }
}

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

sealed class Foo : IFoo {
  int IFoo.Value { get; set; }
}

但是如果我在接口中有一个事件:

interface IFoo {
  event EventHandler Event;
}

并尝试使用 field 显式实现它类似事件:

sealed class Foo : IFoo {
  event EventHandler IFoo.Event;
}

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

错误CS0071:事件的显式接口实现必须使用事件访问器语法

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

所以我的问题是:进行此类限制的设计原因是什么?

Small question about C# language design :))

If I had an interface like this:

interface IFoo {
  int Value { get; set; }
}

It's possible to explicitly implement such interface using C# 3.0 auto-implemented properties:

sealed class Foo : IFoo {
  int IFoo.Value { get; set; }
}

But if I had an event in the interface:

interface IFoo {
  event EventHandler Event;
}

And trying to explicitly implement it using field-like event:

sealed class Foo : IFoo {
  event EventHandler IFoo.Event;
}

I will get the following compiler error:

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

I think that field-like events is the some kind of dualism for auto-implemented properties.

So my question is: what is the design reason for such restriction done?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

倾听心声的旋律 2024-08-29 08:35:41

有趣的问题。我翻阅了语言注释档案,发现这个决定是在 1999 年 10 月 13 日做出的,但注释没有给出该决定的理由。

在我的脑海中,我看不出有任何理论或实践原因解释为什么我们不能有类似领域的显式实现事件。我也不认为我们有任何特别需要这样做的理由。这可能仍是未知之谜之一。

Interesting question. I did some poking around the language notes archive and I discovered that this decision was made on the 13th of October, 1999, but the notes do not give a justification for the decision.

Off the top of my head I don't see any theoretical or practical reason why we could not have field-like explicitly implemented events. Nor do I see any reason why we particularly need to. This may have to remain one of the mysteries of the unknown.

两个我 2024-08-29 08:35:41

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

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() { }
}

请注意,您可以通过首先向上转换到接口来调用该方法:((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;
}

在这里,您甚至无法通过首先向上转换到接口来引发事件,因为事件只能从实现类内部引发。因此,要求显式实现事件的访问器语法似乎是完全有意义的。

I guess it might have to do with the fact that you can't call an explicit interface implementation from other members of the class:

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() { }
}

Note that you can call the method by upcasting to the interface first:((I)this).DoIt();. A bit ugly but it works.

If events could be explicitly implemented as ControlFlow (the OP) suggested, then how would you actually raise them? Consider:

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;
}

Here you cannot even raise the event by upcasting to the interface first, because events can only be raised from within the implementing class. It therefore seems to make perfect sense to require accessor syntax for explicitly implemented events.

燃情 2024-08-29 08:35:41

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

例如,这将触发错误 CS0071:

public delegate void MyEvent(object sender);

interface ITest
{
    event MyEvent Clicked;
}

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

正确的方法是:

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() { }
}

请参阅 编译器错误 CS0071

When explicitly implementing an event that was declared in an interface, you must use manually provide the add and remove event accessors that are typically provided by the compiler. The accessor code can connect the interface event to another event in your class or to its own delegate type.

For example, this will trigger error CS0071:

public delegate void MyEvent(object sender);

interface ITest
{
    event MyEvent Clicked;
}

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

The correct way would be:

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() { }
}

see Compiler Error CS0071

差↓一点笑了 2024-08-29 08:35:41

这实际上并不是我自己的原创想法。

不过,我想我可以回应一下:

“在我的脑海中,我没有看到任何理论或实践原因说明为什么我们不能有类似现场的显式实施事件。我也没有看到任何我们特别需要这样做的原因。这可能仍然是一个未知的奥秘。”
-埃里克·利珀特


在《程序员 C# 简介》第二版的第 23 章中,Eric Gunnerson 写道:

“[I]如果单击按钮时还想调用另一个类,则可以使用 += 运算符,如下所示:

button.Click += new Button.ClickHandler(OtherMethodToCall);

不幸的是,如果其他类不小心,它可能会执行以下操作:

button.Click = new Button.ClickHandler(OtherMethodToCall);

这会很糟糕,因为这意味着我们的 ButtonHandler 将被取消挂钩,并且只会调用新方法。”

...

“需要某种方法来保护委托字段,以便只能使用 += 和 -= 来访问它。”


他在接下来的几页中继续评论包括 add() 和 remove() 方法来实现此行为;能够直接写入这些方法以及为不需要的委托引用分配存储空间的结果。

我想补充更多,但我非常尊重作者,未经他的许可我不会这样做。我建议找到这本书的副本,并会推荐埃里克·冈纳森(Eric Gunnerson)的任何一般内容(博客等......)

无论如何,我希望这与该主题相关,如果是这样,希望它能揭示这个“未知之谜” “? (我正在阅读这一章并搜索 Stack Overflow,以深入了解从自定义对象创建自定义集合时的事件处理程序逻辑注意事项) - 我只提到这一点,因为我在这个特定主题上没有特定的权威。我自己只是一个寻求“启蒙”的学生:-)

This would not actually be an original thought by myself.

However, I thought I might respond to this:

"Off the top of my head I don't see any theoretical or practical reason why we could not have field-like explicitly implemented events. Nor do I see any reason why we particularly need to. This may have to remain one of the mysteries of the unknown."
-Eric Lippert


In Chapter 23 of A Programmer's Introduction to C#, Second Edition, Eric Gunnerson wrote:

"[I]f another class also wanted to be called when the button was clicked, the += operator could be used, like this:

button.Click += new Button.ClickHandler(OtherMethodToCall);

Unfortunately, if the other class wasn't careful, it might do the following:

button.Click = new Button.ClickHandler(OtherMethodToCall);

This would be bad, as it would mean that our ButtonHandler would be unhooked and only the new method would be called."

...

"What is needed is some way of protecting the delegate field so that it is only accessed using += and -=."


He goes on over the next few pages to comment on including the add() and remove() methods to implement this behavior; being able to write to those methods directly and the consequence of storage allocation for unneeded delegate references.

I would add more, but I respect the author too much to do so without his permission. I recommend finding a copy of this book and would recommend anything by Eric Gunnerson in general (blog, etc...)

Anyway, I hope this is relevant to the topic and if so, hope it shines light on this "mystery of the unknown"? (I was reading this very chapter and searching Stack Overflow for insight into event handler logic considerations when creating custom collections from custom objects) - I only mention this because I claim no specific authority on this particular subject. I am merely a student in search of "enlightenment" myself :-)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文