Event Inheritance with C#8 Default Interface Implementation/Traits

雨燕双飞 提交于 2020-06-22 04:12:31

问题


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?


回答1:


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

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


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.

This Sharplab.io example shows that :

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

Generates

    [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.

This is valid :

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.



来源:https://stackoverflow.com/questions/58796545/event-inheritance-with-c8-default-interface-implementation-traits

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!