使用 C#8 默认接口的事件继承 Implementation/Traits
Event Inheritance with C#8 Default Interface Implementation/Traits
目前关于新 C#8 默认接口实现(特征)的事件限制的文档很少。我对 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.
特别困惑
所以问题是:此功能是否已实现并可用?如果是这样,正确的语法是什么?
默认接口成员用于特征,而不仅仅是版本控制,INPC 特征是有意义的。
不幸的是,现在不可能使用 DIM 来引发事件,并且实现这个 seems to be a pain - 这将需要彻底检查事件机制并破坏大量代码,尤其是库代码。我们可以使用 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");
}
}
很遗憾,这是不可能的。这是因为 class 中的 event
关键字生成了一个 支持字段 ,其中包含 事件处理程序 和 add/remove 访问器。当我们引发事件时,我们调用该事件处理程序。
接口不能有状态,这意味着我们无法访问该事件来引发它。
当我们在接口中指定一个事件时,我们创建了一个虚拟事件,编译器只允许 adding/removing 个事件处理程序。提升接口仍然需要访问支持字段。
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));
}
}
我们能做的是添加或删除事件处理程序,但我们甚至无法检查该事件是否已经有其他处理程序。我们冒着多次添加相同事件处理程序的风险。
这是有效的:
interface INPCtrait:System.ComponentModel.INotifyPropertyChanged
{
private void AddSomeDefaultHandler()
{
PropertyChanged+=Something;
}
private void RemoveDefaultHandler()
{
PropertyChanged-=Something;
}
public void Something(Object sender,System.ComponentModel.PropertyChangedEventArgs args)
{
}
}
但我们无法知道是否需要添加该默认处理程序。
目前关于新 C#8 默认接口实现(特征)的事件限制的文档很少。我对 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.
特别困惑所以问题是:此功能是否已实现并可用?如果是这样,正确的语法是什么?
默认接口成员用于特征,而不仅仅是版本控制,INPC 特征是有意义的。
不幸的是,现在不可能使用 DIM 来引发事件,并且实现这个 seems to be a pain - 这将需要彻底检查事件机制并破坏大量代码,尤其是库代码。我们可以使用 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");
}
}
很遗憾,这是不可能的。这是因为 class 中的 event
关键字生成了一个 支持字段 ,其中包含 事件处理程序 和 add/remove 访问器。当我们引发事件时,我们调用该事件处理程序。
接口不能有状态,这意味着我们无法访问该事件来引发它。
当我们在接口中指定一个事件时,我们创建了一个虚拟事件,编译器只允许 adding/removing 个事件处理程序。提升接口仍然需要访问支持字段。
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));
}
}
我们能做的是添加或删除事件处理程序,但我们甚至无法检查该事件是否已经有其他处理程序。我们冒着多次添加相同事件处理程序的风险。
这是有效的:
interface INPCtrait:System.ComponentModel.INotifyPropertyChanged
{
private void AddSomeDefaultHandler()
{
PropertyChanged+=Something;
}
private void RemoveDefaultHandler()
{
PropertyChanged-=Something;
}
public void Something(Object sender,System.ComponentModel.PropertyChangedEventArgs args)
{
}
}
但我们无法知道是否需要添加该默认处理程序。