具有 C#8 默认接口实现/特征的事件继承 [英] Event Inheritance with C#8 Default Interface Implementation/Traits

查看:25
本文介绍了具有 C#8 默认接口实现/特征的事件继承的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

目前关于新的 C#8 默认接口实现(特征)的事件限制的文档很少.我特别困惑 规范提案. 不仅给出了无效的 C# 示例(覆盖"事件缺少标识符),而且在 C#8(VS2019,.NET Core 3.0)中实现这些中的任何一个都会返回一个编译器异常的主机.此外,发行说明对于 C#8,不要提及接口特征的事件.当我继续尝试寻找答案时,我也无法从 开放问题列表.

There is currently little documentation surrounding the limitations of events with the new C#8 default interface implementations (traits). I am particularly confused with the spec proposal. Not only is the example given invalid C# (the "override" event is missing an identifier), but implementing any of these in C#8 (VS2019, .NET Core 3.0) returns a host of compiler exceptions. In addition, the release notes for C#8 don't make any mention of events for interface traits. As I continued to try and track down an answer, I also couldn't gather anything useful from the open issues list.

那么问题是:这个功能是否已实现和可用?如果是这样,正确的语法是什么?

So the questions are: is this feature implemented and usable? If so, what is the proper syntax?

推荐答案

默认接口成员用于特性,而不仅仅是版本控制,INPC 特性是有意义的.

Default interface members are used for traits, not just versioning, and an INPC trait would make sense.

不幸的是,现在无法使用 DIM 引发事件,并且实施此 似乎很痛苦 - 这需要彻底检查事件机制并破坏大量代码,尤其是库代码.我们可以使用 DIM 来添加或删除处理程序,但这不是很有用.

Unfortunately, it's not possible to use DIMs to raise events right now, and implementing this seems to be a pain - it would require overhauling the events mechanism and break a ton of code, especially library code. We can use DIMs to add or remove handlers, but that's not so useful.

如果有这样的东西就好了:

It would be nice to have something like :

interface InpcTrait : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private T Set(T value,String propertyName = "")
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
        return value;
    }
}

class Customer
{
    private string _name;
    public string Name 
    {
        get=>_name;
        set=>_name=Set(value,"Name");
    }
}


不幸的是,这是不可能的.这是因为类中的 event 关键字会生成一个 支持字段,其中包含 事件处理程序 和添加/删除访问器.当我们引发事件时,我们调用该事件处理程序.

Unfortunately, this isn't possible. That's because the event keyword in a class generates a backing field that holds the event handler and add/remove accessors. When we raise the event, we call that event handler.

接口不能有状态,这意味着我们无法访问该事件来引发它.

Interfaces can't have state, which means we can't access that event to raise it.

当我们在接口中指定一个事件时,我们创建了一个虚拟事件,编译器只允许向它添加/删除事件处理程序.提升接口仍然需要访问支持字段.

When we specify an event in an interface, we create a virtual event and the compiler only allows adding/removing event handlers to it. Raising the interface still requires access to the backing field.

这Sharplab.io示例表明:

public class DemoCustomer : INotifyPropertyChanged
{
    // These fields hold the values for the public properties.
    private Guid idValue = Guid.NewGuid();
    private string customerNameValue = String.Empty;
    private string phoneNumberValue = String.Empty;

    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged(String propertyName = "")
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

生成

    [CompilerGenerated]
    private PropertyChangedEventHandler m_PropertyChanged;

    public event PropertyChangedEventHandler PropertyChanged
    {
        [CompilerGenerated]
        add
        {
            //some code
        }
        [CompilerGenerated]
        remove
        {
            //some code
        }
    }

    private void NotifyPropertyChanged(string propertyName = "")
    {
        if (this.m_PropertyChanged != null)
        {
            this.m_PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

我们可以做的是添加或删除事件处理程序,但我们甚至无法检查该事件是否已经有其他处理程序.我们冒着多次添加相同事件处理程序的风险.

What we can do, is add or remove event handlers, but we can't even check whether the event already has other handlers. We risk adding the same event handler multiple times.

这是有效的:

interface INPCtrait:System.ComponentModel.INotifyPropertyChanged
{            
    private  void AddSomeDefaultHandler()
    {
       PropertyChanged+=Something;
    }

    private  void RemoveDefaultHandler()
    {
       PropertyChanged-=Something;
    }

    public void Something(Object sender,System.ComponentModel.PropertyChangedEventArgs args)
    {
    }    
}

但是我们无法知道是否需要添加该默认处理程序.

But we have no way of knowing whether we need to add that default handler or not.

这篇关于具有 C#8 默认接口实现/特征的事件继承的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆