Last active
January 1, 2018 19:35
-
-
Save IanSavchenko/d32ec4024f0b1a97e33874ff5d4c214c to your computer and use it in GitHub Desktop.
Monitorable C#
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Collections.Generic; | |
| using System.Threading; | |
| using System.Threading.Tasks; | |
| namespace IanSavchenko.Tools | |
| { | |
| /// <summary> | |
| /// Represents a source for monitorable object - something that has a value and can change later | |
| /// </summary> | |
| public class MonitorableSource<T> | |
| { | |
| private T _value; | |
| public MonitorableSource() | |
| { | |
| Monitorable = new Monitorable<T>(this); | |
| } | |
| public Monitorable<T> Monitorable { get; } | |
| public T Value | |
| { | |
| get { return _value; } | |
| set | |
| { | |
| var prevValue = _value; | |
| _value = value; | |
| if (!EqualityComparer<T>.Default.Equals(prevValue, value)) | |
| Updated?.Invoke(this, new MonitorableUpdatedEventArgs<T>(value)); | |
| } | |
| } | |
| public event EventHandler<MonitorableUpdatedEventArgs<T>> Updated; | |
| public static explicit operator MonitorableSource<T>(T value) | |
| { | |
| return new MonitorableSource<T>() { _value = value }; | |
| } | |
| } | |
| /// <summary> | |
| /// Represents a read-only object which value can be accessed and value changed noitifications can be subscribed to | |
| /// </summary> | |
| public class Monitorable<T> | |
| { | |
| private readonly MonitorableSource<T> _source; | |
| public Monitorable(MonitorableSource<T> source) | |
| { | |
| _source = source; | |
| } | |
| public T Value => _source.Value; | |
| public event EventHandler<MonitorableUpdatedEventArgs<T>> Updated | |
| { | |
| add { _source.Updated += value; } | |
| remove { _source.Updated -= value; } | |
| } | |
| } | |
| /// <inheritdoc /> | |
| /// <summary> | |
| /// Event arguments for monitorable updated | |
| /// </summary> | |
| /// <typeparam name="T"></typeparam> | |
| public class MonitorableUpdatedEventArgs<T> : EventArgs | |
| { | |
| public MonitorableUpdatedEventArgs(T updatedValue) | |
| { | |
| UpdatedValue = updatedValue; | |
| } | |
| public T UpdatedValue { get; } | |
| } | |
| /// <summary> | |
| /// Handy utils for monitorable | |
| /// </summary> | |
| public static class MonitorableExtensions | |
| { | |
| /// <summary> | |
| /// Asynchronously waits for <paramref name="monitorable"/> to get a <paramref name="value"/> | |
| /// </summary> | |
| /// <returns>Returns a Task which is resolved when monitorable gets specified <paramref name="value"/></returns> | |
| public static Task<T> WaitForValue<T>(this Monitorable<T> monitorable, T value, CancellationToken cancellationToken = default(CancellationToken)) | |
| { | |
| var tcs = new TaskCompletionSource<T>(); | |
| cancellationToken.Register(() => tcs.TrySetCanceled()); | |
| var updatedDelegate = new EventHandler<MonitorableUpdatedEventArgs<T>>((sender, args) => | |
| { | |
| if (EqualityComparer<T>.Default.Equals(args.UpdatedValue, value)) | |
| tcs.TrySetResult(value); | |
| }); | |
| monitorable.Updated += updatedDelegate; | |
| // when task resolved - unsubscribing | |
| tcs.Task.ContinueWith(t => monitorable.Updated -= updatedDelegate); | |
| if (EqualityComparer<T>.Default.Equals(monitorable.Value, value)) | |
| tcs.TrySetResult(value); | |
| return tcs.Task; | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment