Есть ли способ вызвать метод, когда установлено какое-либо свойство класса? - PullRequest
6 голосов
/ 18 апреля 2009

Итак, я пытаюсь вызвать единственную функцию propertyWasSet (), когда любое свойство в классе C # установлено (и наоборот, propertyWasGot (), когда оно получено). Я также хотел бы знать, какое свойство 'get' было вызвано.

Я хотел бы сохранить список свойств, которые «установлены», и проверить действие «get», если они были установлены (и выдать ошибку, если это не так).

Я просматриваю документацию msdn для размышлений, делегатов и т. Д., Но я не совсем уверен, что это возможно.

Есть ли способ сделать это? или вызвать событие при вызове одной из этих функций, которые могут быть перехвачены в базовом классе или что-то еще?

Ответы [ 5 ]

8 голосов
/ 18 апреля 2009

На прошлой неделе я написал перехватчик для Set, который можно легко расширить для Get, он использует RealProxy, что означает, что ваш базовый класс должен наследовать MarshalByRefObject.

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

Также вы можете посмотреть на генераторы кода, чтобы обойти это или PostSharp ...

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

public interface IInterceptorNotifiable {
    void OnPropertyChanged(string propertyName);
}

/// <summary>
/// A simple RealProxy based property interceptor
/// Will call OnPropertyChanged whenever and property on the child object is changed
/// </summary>
public class Interceptor<T> where T : MarshalByRefObject, IInterceptorNotifiable, new() {

    class InterceptorProxy : RealProxy {
        T proxy; 
        T target;
        EventHandler<PropertyChangedEventArgs> OnPropertyChanged;

        public InterceptorProxy(T target)
            : base(typeof(T)) {
            this.target = target;
        }

        public override object GetTransparentProxy() {
            proxy = (T)base.GetTransparentProxy();
            return proxy;
        }


        public override IMessage Invoke(IMessage msg) {

            IMethodCallMessage call = msg as IMethodCallMessage;
            if (call != null) {

                var result = InvokeMethod(call);
                if (call.MethodName.StartsWith("set_")) {
                    string propName = call.MethodName.Substring(4);
                    target.OnPropertyChanged(propName);
                } 
                return result;
            } else {
                throw new NotSupportedException();
            } 
        }

        IMethodReturnMessage InvokeMethod(IMethodCallMessage callMsg) {
            return RemotingServices.ExecuteMessage(target, callMsg);
        }

    }

    public static T Create() {
        var interceptor = new InterceptorProxy(new T());
        return (T)interceptor.GetTransparentProxy();
    }


    private Interceptor() {
    }

}

Использование:

  class Foo : MarshalByRefObject, IInterceptorNotifiable {
        public int PublicProp { get; set; }
        public string lastPropertyChanged;

        public void OnPropertyChanged(string propertyName) {
            lastPropertyChanged = propertyName;
        }

    }


    [Test]
    public void TestPropertyInterception() {

        var foo = Interceptor<Foo>.Create();
        foo.PublicProp = 100;

        Assert.AreEqual("PublicProp", foo.lastPropertyChanged);

    }
}
3 голосов
/ 18 апреля 2009

Вы можете посмотреть на PostSharp для такого рода задач. Он предназначен для работы поверх C # (или любого другого языка .NET в этом отношении) и имеет то преимущество, что не загромождает ваш код дополнительными отражениями. На самом деле, я не верю, что вы могли бы найти решение, которое бы просто использовало C # / Reflection, не добавляя код вручную в каждое из ваших свойств, поэтому я определенно рекомендую PostSharp в качестве пути.

0 голосов
/ 29 апреля 2009

Часть SET вашего запроса очень похожа на систему свойств зависимостей WPF. Но часть GET настолько необычна, что отсутствует даже в системе свойств зависимостей WPF!

0 голосов
/ 18 апреля 2009

Ничего подобного нет, если вы сами не создадите это.

0 голосов
/ 18 апреля 2009

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

...