【问题标题】:Adding functionality to interfaces/classes through C# attributes?通过 C# 属性向接口/类添加功能?
【发布时间】:2012-03-28 20:02:25
【问题描述】:

我很难以谷歌查询的形式总结我的问题(也许我的 foo 已关闭):

我试图通过不编辑类型定义本身,而是通过使用接口修饰对象来为接口或类提供一些功能。我正在尝试的简单示例是附加一个名为 [Notify] 的属性,该属性定义了一个属性更改事件,理想情况下,为该事件的接口/类提供使用。我没有成功,所以我向任何可能的设备(如果有的话)开放以实现等效:

[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# attributes custom-attributes


    【解决方案1】:

    您正在寻找的是挂钩诸如方法调用之类的事件并将一些操作附加到该事件。这不是 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 );            
        }
    }
    

    你可以找到here的实现细节。

    用法很简单:

    [Notify]
    public class Person
    {
        public string Name { get; set; }
    }
    

    请记住,实际代码将在编译期间注入到程序集中。属性不能添加任何功能。它们只是元数据。在这种情况下,PostSharp 使用元数据生成代码并将其注入程序集。

    【讨论】:

      【解决方案2】:

      属性通常不任何事情。它们的目的更多是为它们装饰的类型/字段/属性/等提供描述符或元数据

      一般的替代方法可能是使用扩展方法,但我认为这也不适用于您的情况,因为您正在尝试将事件添加到类型中。

      我能想到的唯一可行的选择是使用 PostSharp 或其他 AOP 框架之类的东西来进行一些代码编织后编译。

      【讨论】:

        猜你喜欢
        • 2015-01-24
        • 2016-10-11
        • 1970-01-01
        • 2023-03-28
        • 2018-04-05
        • 1970-01-01
        • 2012-03-11
        • 2011-11-28
        • 2013-07-11
        相关资源
        最近更新 更多