当属性或变量更改值时触发事件



我想向我拥有的项目添加更多功能,该项目使用NET框架中打包的许多类。这些相同的类提供了许多属性,这些属性在适应我的项目功能时非常有用,但是这些类缺少的一件事是事件。

如果每个属性都有一个适当的事件,每当此类属性的值更改时都会触发该事件,那么我可以分配一个事件处理程序,该处理程序将基于这些属性值进行操作。

我在下面做了一个示例案例,以我能想到的最简单的方式来说明我的目标。

示例案例:

System.Net.Sockets.Socket类(MSDN 文档上的套接字)具有属性 命名Connected如果套接字为 连接到指定的端点,否则返回 false。

我想完成的事情很简单。我想保留这个 属性在"监视"下,当它的值发生变化时,触发一个事件。

对我自己的一个类执行此操作会很简单,尽管使用 INotifyPropertyChanged 接口有点烦人,仅仅是因为我的代码总是更改属性的值,我必须手动触发事件。不幸的是,据我所知,即使是这种过程也不能应用于 NET Framework 中分布的现有Socket类。

好吧,这个问题变得相当广泛,对不起,但我希望它能让我了解我的目标。

现在简单地说,我想观察 Socket 类的 Connected 属性,当它的值发生变化时,触发一个事件。如果也可以使用这种方法来观察变量以及属性,那将非常棒,不仅对我,而且对于每个偶然发现这个问题的人来说都是如此。

当然,简单轻量级的方法更受欢迎,但最重要的是,我想了解如何完成它,以便将来我可以将其大规模应用于其他类。

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

任何问题都只是问。

我实现了一个应该让你入门的基本类。 我敢肯定,一个功能齐全、生产就绪、线程安全的类需要更多的工作,而且你需要实现自己的策略,以确定何时轮询值变化。

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 实例浮动并减少接线/手动代码的数量。 但至少这应该是一个开始。

你要找的是观察者模式的实现。 像这样的东西Observable<T>实现可能会起作用。

另请参阅 .NET 4 中的IObserver<T>接口:

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

相关内容

  • 没有找到相关文章

最新更新