Fire event when a property or variable changes value

后端 未结 2 1468
长发绾君心
长发绾君心 2021-01-14 03:56

I want to add more functionality to a project I have that makes use a number of classes packaged in the NET Framework. These same classes provide a number of properties whic

相关标签:
2条回答
  • 2021-01-14 04:35

    What your looking for is an implementation of the Observer Pattern. Something like this Observable<T> implementation might work.

    See also the IObserver<T> Interface in .NET 4:

    The IObserver<T> and IObservable<T> interfaces provide a generalized mechanism for push-based notification. The IObservable<T> interface represents the class that sends notifications (the provider); the IObserver<T> interface represents the class that receives them (the observer). T represents the class that provides the notification information.

    0 讨论(0)
  • 2021-01-14 04:42

    I implemented a basic class that should get you started. I'm sure a fully functional, production-ready, thread-safe class would require a bit more work, plus you need to implement your own strategy for when to poll for value changes.

    public class TargettedObserver<T>
    {
        private static readonly EqualityComparer<T> EqualityComparer = EqualityComparer<T>.Default;
    
        private Func<T> ValueTarget;
        private T OldValue;
    
        public event ObservedValueChangedEventHandler<T> ValueChanged;
    
        public TargettedObserver(Func<T> valueTarget)
        {
            this.ValueTarget = valueTarget;
            OldValue = ObtainCurrentValue();
        }
    
        public bool CheckValue()
        {
            T oldValue = OldValue;
            T newValue = ObtainCurrentValue();
    
            bool hasValueChanged = CompareValues(oldValue, newValue);
    
            if (hasValueChanged)
            {
                OldValue = newValue;
                NotifyValueChanged(oldValue, newValue);
            }
    
            return hasValueChanged;
        }
    
        private void NotifyValueChanged(T oldValue, T newValue)
        {
            var valueChangedEvent = ValueChanged;
            if (valueChangedEvent != null)
                valueChangedEvent(this, new ObservedValueChangedEventArgs<T>(oldValue, newValue));
        }
    
        private static bool CompareValues(T oldValue, T newValue)
        {
            return !EqualityComparer.Equals(oldValue, newValue);
        }
    
        private T ObtainCurrentValue()
        {
            return ValueTarget();
        }
    }
    

    And the event handling:

    public class ObservedValueChangedEventArgs<T> : EventArgs
    {
        public T OldValue { get; private set; }
        public T NewValue { get; private set; }
    
        public ObservedValueChangedEventArgs(T oldValue, T newValue)
        {
            this.OldValue = oldValue;
            this.NewValue = newValue;
        }
    }
    
    public delegate void ObservedValueChangedEventHandler<T>(TargettedObserver<T> observer, ObservedValueChangedEventArgs<T> eventArgs);
    

    Usage looks something like this:

    public class TestClass
    {
        private Socket MySocket;
        private static TargettedObserver<bool> SocketConnectedObserver;
    
        public void Main()
        {
            MySocket = new Socket();
            SocketConnectedObserver = new TargettedObserver<bool>(() => MySocket.Connected);
            SocketConnectedObserver.ValueChanged += ReportSocketConnectedStateChanged;
            PerformSocketConnection();
    
            MainThread.Invoke(PollSocketValue);
        }
    
        private void PollSocketValue()
        {
            SocketConnectedObserver.CheckValue();
            MainThread.Invoke(PollSocketValue);
        }
    
        private void ReportSocketConnectedStateChanged(TargettedObserver<bool> observer, ObservedValueChangedEventArgs<bool> eventArgs)
        {
            Console.WriteLine("Socket connection state changed!  OldValue: " + eventArgs.OldValue + ", NewValue: " + eventArgs.NewValue);
        }
    }
    

    Notice the constructor takes a simple lambda expression that can evaluate the value you're wanting to observe.

    Also note that MainThread.Invoke is just a pseudocode to show it polling for a change on every main thread loop. I'm sure there are nicer strategies (background thread with a timer interval) for example that could be implemented in a nice, reusable way. Still more work to be done in terms of deregistering the observer. Could probably make some nice factory methods or lambda delegates so you don't need to keep the TargettedObserver instance floating around and reduce the amount of wiring/manual code. But at least this should be a start.

    0 讨论(0)
提交回复
热议问题