C # - Перехват изменений свойств в подклассах - PullRequest
7 голосов
/ 21 мая 2011

Я нахожусь в процессе создания каркаса, в котором я предоставляю базовый класс, и разработчики каркаса будут наследовать от базового класса и предоставлять дополнительные свойства и методы.В базовом классе я хотел бы иметь способ наблюдения, когда значение свойства изменяется.Свойство может быть из базового класса или любого из подклассов.Я знаю, что с помощью отражения я могу определить список свойств из любого экземпляра, но есть ли способ отследить изменение значения свойства?

Вот очень упрощенный пример того, что я говорю:

public class BaseClass
{
    public string BaseClassProperty { get; set; }

    public void DoSomethingWhenEitherPropertyGetsChanged()
    {

    }
}

public class SubClass : BaseClass
{
    public string SubClassProperty { get; set; }
}

Что я могу сделать, чтобы DoSomethingWhenEitherPropertyGetsChanged был запущен, когда любое из свойств изменило свое значение.

Ответы [ 4 ]

4 голосов
/ 21 мая 2011

Вы можете использовать notifypropertyweaver для этой цели. Это именно то, что вы хотите. Вот ссылка:

С домашней страницы с открытым исходным кодом:

Использует IL-ткачество (через http://www.mono -project.com / Cecil ) для внедрения кода INotifyPropertyChanged в свойства.

  • Атрибуты не требуются
  • Ссылки не требуются
  • Базовый класс не требуется
  • Поддерживает .net 3.5, .net 4, Silverlight 3, Silverlight 4, Silverlight 5 и Windows Phone 7
  • Поддерживает режим профиля клиента
3 голосов
/ 21 мая 2011

Я бы, вероятно, использовал Postsharp и создал бы унаследованный атрибут, внедряющий код перехвата во все открытые свойства.Пометка атрибута как унаследованного также должна автоматически присоединять его ко всем подклассам.

1 голос
/ 21 мая 2011

Я написал свое собственное представление о ваших требованиях, но я не уверен, соответствует ли он вашим потребностям. Измененное INotifyProperty - это то, что вы тоже можете посмотреть, но мне это не очень нравится, потому что это похоже на соединение спегетти. Возможно, это даст вам некоторые творческие идеи.

Это позволяет вам использовать ObservableObject для всех типов ваших свойств. Таким образом, каждое свойство будет иметь событие ObjectChanged, к которому вы можете подключиться. Преимущества заключаются в том, что вы должны инициализировать все свои свойства в конструкторе, чтобы исключить исключение NullReferenceException где-то в вашем коде.

В этом примере используются три класса.

  • ObservableObject.cs
  • Employee.cs
  • Program.cs

ObservableObject.cs

    //-----------------------------------------------------------------------------
    // <copyright file="ObservableObject.cs" company="DCOM Productions">
    //     Copyright (c) DCOM Productions.  All rights reserved.
    // </copyright>
    //-----------------------------------------------------------------------------

    namespace PropertyChangedEventExample {
        using System;

        public class ObservableObject : Object {
            /// <summary>
            /// Expose the default constructor
            /// </summary>
            public ObservableObject() {
                // No default implementation
            }

            private object m_Object = null;
            /// <summary>
            /// Base object
            /// </summary>
            public object Object {
                get {
                    return m_Object;
                }
                set {
                    if (m_Object != value) {
                        m_Object = value;
                        OnObjectChanged(this, EventArgs.Empty);
                    }
                }
            }

            /// <summary>
            /// Triggered when the value of this object has changed.
            /// </summary>
            public event System.EventHandler<EventArgs> ObjectChanged;
            /// <summary>
            /// EventHandler wire-up
            /// </summary>
            protected virtual void OnObjectChanged(object sender, System.EventArgs e) {
                if (ObjectChanged != null) {
                    ObjectChanged(sender, e);
                }
            }

            /// <summary>
            /// Gets the value
            /// </summary>
            public object Get() {
                return this.Object;
            }

            /// <summary>
            /// Sets the value
            /// </summary>
            public void Set(object value) {
                this.Object = value;
            }
        }
    }

Employee.cs

    //-----------------------------------------------------------------------------
    // <copyright file="Employee.cs" company="DCOM Productions">
    //     Copyright (c) DCOM Productions.  All rights reserved.
    // </copyright>
    //-----------------------------------------------------------------------------

    namespace PropertyChangedEventExample {
        using System;

        public class Employee {
            /// <summary>
            /// Expose default constructor
            /// </summary>
            public Employee() {
                Name = new ObservableObject();
            }

            /// <summary>
            /// Gets or sets the name
            /// </summary>
            public ObservableObject Name {
                get;
                set;
            }
        }
    }

Program.cs

    //-----------------------------------------------------------------------------
    // <copyright file="Program.cs" company="DCOM Productions">
    //     Copyright (c) DCOM Productions.  All rights reserved.
    // </copyright>
    //-----------------------------------------------------------------------------

    namespace PropertyChangedEventExample {
        using System;

        class Program {
            static void Main(string[] args) {
                Employee employee = new Employee();
                employee.Name.Set("David");
                employee.Name.ObjectChanged += new EventHandler<EventArgs>(Name_ObjectChanged);
                employee.Name.Set("Dave");
                Console.ReadKey(true);
            }

            static void Name_ObjectChanged(object sender, EventArgs e) {
                ObservableObject employee = sender as ObservableObject;
                Console.WriteLine("Name changed to {0}", employee.Get());
            }
        }
    }
0 голосов
/ 21 мая 2011

Лучшим вариантом будет то, что рекомендовал CrisWue, и используйте postsharp или какой-либо другой постпроцессор, чтобы ввести поведение в ваши свойства. Кроме этого, я думаю, вам нужно будет вручную вызывать DoSomethingWhenEitherPropertyGetsChanged () в своих свойствах.

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

...