Добавление функциональности к интерфейсам / классам через атрибуты C #? - PullRequest
0 голосов
/ 29 марта 2012

У меня возникают трудности при попытке подвести итог моего вопроса в виде запроса Google (может быть, мой 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 больше функциональности, не меняя определения (т.е. не добавляя интерфейс или базовый класс). Я понимаю, что атрибуты тоже меняются, но я доволен подходом метаданных.

Заранее благодарим за любой свет, который можно пролить.

Ответы [ 2 ]

1 голос
/ 29 марта 2012

То, что вы ищете, это подключать такие события, как вызовы методов и прикрепление некоторых действий к этим событиям. Это не особенность C # по умолчанию, но это может быть сделано с помощью такой инфраструктуры AOP, как PostSharp . PostSharp добавляет эту функциональность, изменяя код во время сборки (он не использует Reflection).

Вот что вам нужно реализовать с помощью 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 для генерации кода и внедрения его в сборку.

1 голос
/ 29 марта 2012

Атрибуты обычно не делают ничего. Их целью является предоставление дескрипторов или мета данных для типов / полей / свойств / и т. Д., Которые они украшают.

Общая альтернатива может заключаться в использовании методов расширения, но я не думаю, что это сработает и в вашем случае, потому что вы пытаетесь добавить событие в тип.

Единственная жизнеспособная альтернатива, о которой я могу подумать, - это использовать что-то вроде PostSharp или другой AOP-фреймворк для выполнения пост-компиляции кода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...