開始するための基本的なクラスを実装しました。完全に機能し、本番環境に対応し、スレッドセーフなクラスを作成するには、もう少し作業が必要になると確信しています。さらに、値の変更をいつポーリングするかについて、独自の戦略を実装する必要があります。
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);
}
}
コンストラクターは、観察したい値を評価できる単純なラムダ式を取ることに注意してください。
MainThread.Invoke
また、すべてのメイン スレッド ループで変更をポーリングすることを示す単なる擬似コードであることに注意してください。たとえば、再利用可能な優れた方法で実装できる、より優れた戦略 (タイマー間隔のあるバックグラウンド スレッド) があると確信しています。オブザーバーの登録解除に関しては、さらに多くの作業が必要です。おそらくいくつかの素敵なファクトリ メソッドまたはラムダ デリゲートを作成できるので、TargettedObserver インスタンスをあちこちに浮かせておく必要がなく、配線/手動コードの量を減らすことができます。しかし、少なくともこれはスタートであるべきです。