属性或变量更改值时的Fire事件

时间:2012-06-28 21:26:24

标签: c# events variables properties inotifypropertychanged

我想为我所拥有的项目添加更多功能,这些项目使用了.NET Framework中打包的许多类。这些相同的类提供了许多属性,这些属性可以非常有用地适应我的项目的功能,但是这些类缺少的一件事是事件。

如果每个属性都有一个适当的事件,只要这个属性的值发生变化就会触发,我可以根据这些属性值分配一个事件处理程序。

我制作了一个示例案例,以最简单的方式说明我的目标。

  

示例案例

     

System.Net.Sockets.Socket类(Socket on MSDN Docs)有一个属性   名为Connected,如果套接字基本上返回true   连接到指定的终点,否则返回false。

     

我想要完成的事情很简单。我想保留这个   “观察”下的属性,当它的值发生变化时,触发一个事件。

对我自己的一个类来说这很简单,虽然使用INotifyPropertyChanged interface有点令人讨厌,只是因为我的代码总是改变了我必须手动触发事件的属性值。不幸的是,据我所知,甚至这种程序也不适用于在.NET Framework中分发的现有Socket类。

嗯,这个问题变得非常广泛,对不起,但我希望它能够深入了解我的目标。

现在简单地说,我想看Connected类的Socket属性,当它的值发生变化时,触发一个事件。如果有可能也使用这样的方法来观察变量以及属性,那将是非常棒的,不仅对我而言,对于每个在SO上遇到这个问题的人都会很棒。

当然首选简单轻量级的方法,但最重要的是,我想了解它是如何完成的,所以将来我可以将它大规模地应用到其他类中。

我意识到我问了很多。非常感谢。

任何问题都可以问。

2 个答案:

答案 0 :(得分:1)

我实现了一个可以帮助你入门的基础课程。我确信一个功能齐全,生产就绪,线程安全的类需要更多的工作,而且你需要实现自己的策略来何时轮询值的变化。

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();
    }
}

事件处理:

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);

用法看起来像这样:

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);
    }
}

请注意,构造函数采用一个简单的lambda表达式,可以计算您想要观察的值。

另请注意,MainThread.Invoke只是一个伪代码,用于显示轮询每个主线程循环的更改。我确信有更好的策略(具有定时器间隔的后台线程),例如可以以漂亮,可重用的方式实现。在取消注册观察者方面还有许多工作要做。可能会创建一些漂亮的工厂方法或lambda委托,因此您不需要保持TargettedObserver实例浮动并减少布线/手动代码的数量。但至少这应该是一个开始。

答案 1 :(得分:0)

您正在寻找的是Observer Pattern的实施。像this Observable<T> implementation之类的东西可能有用。

另请参阅.NET 4中的IObserver<T> Interface

  

IObserver<T>IObservable<T>接口提供了通用化   基于推送的通知机制。 IObservable<T>接口表示该类   发送通知(提供者); IObserver<T>界面   表示接收它们的类(观察者)。 T代表   提供通知信息的类。