使用 C#8 默认接口实现/特征的事件继承

jef*_*237 6 c# .net-core c#-8.0 default-interface-member

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

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

Pan*_*vos 6

默认接口成员用于特征,而不仅仅是版本控制,并且 INPC 特征是有意义的。

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

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

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


Run Code Online (Sandbox Code Playgroud)

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

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

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

这个 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));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

生成

    [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));
        }
    }
Run Code Online (Sandbox Code Playgroud)

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

这是有效的:

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

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

    public void Something(Object sender,System.ComponentModel.PropertyChangedEventArgs args)
    {
    }    
}
Run Code Online (Sandbox Code Playgroud)

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