Запустить событие / функцию на имущество? (С #) - PullRequest
10 голосов
/ 06 августа 2009

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

Как создать событие / функцию, которая запускается при изменении свойства?

Дополнительно
Он изменяется только в своем собственном классе, напрямую на базовую частную переменную.

1009 * Е.Г. *

private bool m_MyValue = false;

public bool MyValue
  {
  get { return m_MyValue; }
  }

private void SomeFunction()
  {
  m_MyValue = true;
  }

Ответы [ 8 ]

10 голосов
/ 06 августа 2009

Вы не можете, в основном ... не без использования чего-либо вроде API отладчика для внедрения кода во время выполнения и изменения IL исходной библиотеки (и я не рекомендую ни одно из этих решений; кроме всего прочего это может нарушить лицензию библиотеки).

В основном, если свойство не поддерживает уведомление, оно не поддерживает уведомление. Вы должны искать другой способ решения вашей проблемы. (Будет ли работать опрос, например?)

5 голосов
/ 06 августа 2009

Вы не можете сделать это напрямую [как сказал Джон Скит], если только он не виртуальный, у вас есть возможность перехватывать все экземпляры экземпляров класса, и нет никаких изменений в вспомогательном поле, которое влияет на реальное «значение» пророк.

Единственный способ применения грубой силы - это использовать Mono.Cecil или MS CCI для настройки установки пропеллера на DimeCast на Cecil . (Или PostSharp)

Однако это не приведет к внутренним изменениям в резервном поле (если оно есть). (Вот почему упаковка, вероятно, не сработает).

ОБНОВЛЕНИЕ: Учитывая ваше обновление, которое вы определенно пытаетесь отловить, лежащие в основе изменения поля, единственный способ сделать это - использовать PS / CCI / Cecil и проанализировать поток, чтобы перехватить все обновления поля. Короче, не очень выполнимо.

3 голосов
/ 06 августа 2009

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

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

Вот простой пример того, о чем я говорю:

public class SomeProxy
{
    public SomeProxy(ExternalObject obj)
    {
         _obj = obj;
    }

    public event EventArgs PropertyChanged;

    private bool _lastValue;

    private ExternalObject _obj;

    protected virtual void OnPropertyChanged()
    {
        if(PropertyChanged != null)
            PropertyChanged();
    }

    protected virtual void PreMethodCall()
    {
        _lastValue = _obj.SomeProperty;
    }

    protected virtual void PostMethodCall()
    {
        if(_lastValue != _obj.SomeProperty)
            OnPropertyChanged();
    }

    // Proxy method.
    public SomeMethod(int arg)
    {
        PreMethodCall();
        _obj.SomeMethod(arg); // Call actual method.
        PostMethodCall();
    }
}

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

2 голосов
/ 06 августа 2009

Как упоминалось ранее, самый прямой метод (и тот, который требует наименьшего изменения кода) - это использование библиотеки AOP, такой как PostSharp.

Однако решение может быть достигнуто с использованием традиционного C # / .NET с использованием свойства зависимостей pattern , которое использовалось во всем WPF для достижения эффекта Я предлагаю прочитать об этом и рассмотреть возможность внедрения такой системы (или, по крайней мере, упрощенной версии) для вашего проекта, если это уместно.

1 голос
/ 06 августа 2009

Не могли бы вы унаследовать от класса и скрыть свойство? Как то так ...

class MyClass : BaseClass
{
    // hide base property.
    public new bool MyProperty
    {
        get
        {
            return base.MyProperty;
        }

        set
        {
            base.MyProperty = value;
            RaiseMyPropertyChangedEvent();
        }
    }
}
1 голос
/ 06 августа 2009

Вам нужно будет создать класс, который обернет класс в dll, в свойстве setter просто вызовите событие, используя обычные методы.

0 голосов
/ 06 августа 2009

Я думаю, что идея Алекса об обертке хороша, однако, учитывая, что самое важное для вас, это то, что вы знаете, что значение изменяется перед использованием , вы можете просто переместить уведомление в добытчик, обходя заботы о внутреннем изменении стоимости. Таким образом, вы получаете что-то похожее на опрос, но надежное:

class MyClass : BaseClass
{
    //local value
    private bool local;

    //first access yet?
    private bool accessed = false;

    // Override base property.
    public new bool MyProperty
    {
        get
        {
            if(!accessed)
            {
                // modify first-get case according to your taste, e.g.
                local = base.MyProperty;
                accessed = true;
                RaiseMyPropertyChangedBeforeUseEvent();
            }
            else
            {
                if(local != base.MyProperty)
                {
                    local = base.MyProperty;
                    RaiseMyPropertyChangedBeforeUseEvent();
                }
            }

            return local;
        }

        set
        {
            base.MyProperty = value;
        }
    }
}
0 голосов
/ 06 августа 2009

Вы можете попытаться унаследовать его и использовать вместо него дочерний. Переопределите «набор» свойства, чтобы оно вызывало событие.

РЕДАКТИРОВАТЬ: ... только если свойство является родительским в родительском классе ...

...