通过C#属性向接口/类添加功能
本文关键字:添加 功能 接口 属性 通过 | 更新日期: 2023-09-27 18:29:14
我很难用谷歌查询的形式总结我的问题(也许我的foo关闭了):
我试图通过不编辑类型定义本身,而是用接口来修饰对象,从而为接口或类提供一些功能。我尝试的一个简单示例是附加一个名为[Notify]的Attribute,它定义了一个属性更改事件,理想情况下,为接口/类提供事件的使用。我一直没有成功,所以我正在向任何可能的设备(如果有的话)开放,以实现同等效果:
[Notify]
public interface IPerson
{
string Name { get; set; }
}
[AttributeUsage(AttributeTargets.Interface, AllowMultiple = false, Inherited = false)]
public class Notify: Attribute
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
使用IPerson:
IPerson person = PersonFactory.create();
person.PropertyChanged += SomeDelegateHere // the center peice
当然,如果您复制了这段代码,那个人就不会有PropertyChanged。无论是否具有属性,是否有一种方法可以在不更改定义(即不添加接口或基类)的情况下为IPerson提供更多功能。我知道属性也在变化,但我对元数据方法感到满意。
提前感谢您提供的任何光线。
您所看到的是挂接诸如方法调用之类的事件,并将一些操作附加到这些事件。这不是C#的默认特性,但可以通过PostSharp这样的AOP框架来实现。PostSharp通过在构建时更改代码来添加此功能(它不使用反射)。
以下是您需要使用PostSharp:实现的内容
[Serializable]
[IntroduceInterface(typeof(INotifyPropertyChanged), OverrideAction = InterfaceOverrideAction.Ignore)]
[MulticastAttributeUsage(MulticastTargets.Class, Inheritance = MulticastInheritance.Strict )]
public class NotifyAttribute : InstanceLevelAspect, INotifyPropertyChanged
{
[ImportMember("OnPropertyChanged", IsRequired = false)]
public Action<string> OnPropertyChangedMethod;
[IntroduceMember(Visibility = Visibility.Family, IsVirtual = true, OverrideAction = MemberOverrideAction.Ignore)]
public void OnPropertyChanged( string propertyName )
{
if (PropertyChanged != null )
PropertyChanged(Instance, new PropertyChangedEventArgs(propertyName));
}
[IntroduceMember(OverrideAction = MemberOverrideAction.Ignore)]
public event PropertyChangedEventHandler PropertyChanged;
[OnLocationSetValueAdvice]
[MulticastPointcut(Targets = MulticastTargets.Property, Attributes = MulticastAttributes.Instance)]
public void OnPropertySet( LocationInterceptionArgs args )
{
if (args.Value == args.GetCurrentValue()) return;
args.ProceedSetValue();
this.OnPropertyChangedMethod.Invoke( args.Location.Name );
}
}
您可以在此处找到实施详细信息。
用法很简单:
[Notify]
public class Person
{
public string Name { get; set; }
}
请记住,实际的代码将在编译期间注入到程序集中。属性无法添加任何功能。它们只是元数据。在这种情况下,PostSharp使用元数据生成代码并将其注入程序集中。
属性通常不会做任何事情。它们的目的更多的是为它们装饰的类型/字段/属性等提供描述符或meta数据。
一个通用的替代方法可能是使用扩展方法,但我认为这在您的情况下也不起作用,因为您正试图将事件添加到类型中。
我能想到的唯一可行的替代方案是使用PostSharp或其他AOP框架来进行一些代码编织后编译。