-
-
Save gowland/5313861 to your computer and use it in GitHub Desktop.
Invalidatable monad inspired by Eric Lippert's series on monads. I intended to use this class to wrap data that is expensive to generate but that may not be valid for the duration of the application's life time.I ended not using it, so it is unproven and untested and provided mostly for my own reference.
This file contains 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
public class Invalidatable<T> | |
{ | |
public T Value { get; private set; } | |
public Func<bool> IsInvalidated { get; private set; } | |
public Invalidatable(T value, Func<bool> isInvalidated) | |
{ | |
Value = value; | |
this.IsInvalidated = isInvalidated; | |
} | |
public Invalidatable(T value) : this(value, () => false) { } | |
public static Invalidatable<R> Bind<A, R>( | |
Invalidatable<A> invalidatable, Func<A, Invalidatable<R>> function) | |
{ | |
Invalidatable<R> result = function(invalidatable.Value); | |
return new Invalidatable<R>(result.Value, () => invalidatable.IsInvalidated() || result.IsInvalidated()); | |
} | |
} |
This file contains 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
/// Example usage | |
class MyDataSource | |
{ | |
private bool IsStillValid(ExpensiveComputedData computed) | |
{ | |
// Insert logic here to determine whether or not the class is still valid | |
return true; | |
} | |
public Invalidatable<ExpensiveComputedData> GetExpensiveComputedData() | |
{ | |
//Calculate data | |
ExpensiveComputedData computed = new ExpensiveComputedData(); | |
return new Invalidatable<ExpensiveComputedData>(computed, () => !this.IsStillValid(computed)); | |
} | |
} | |
class MyDataClient | |
{ | |
public MyDataSource Data {get; private set}; | |
private Invalidatable<ExpensiveComputedData> Computed; | |
private trustedTime = 24; | |
public MyDataClient(MyDataSource data) | |
{ | |
Data = data; | |
// Get the computed data | |
Computed = data.GetExpensiveComputedData(); | |
} | |
// Derive data from the invalidatable data that is time dependent | |
private static Invalidatable<int> DerivitiveCalculation(Invalidatable<ExpensiveComputedData> computedValue) | |
{ | |
// Timeout in 24 hours | |
DateTime timeoutDate = DateTime.UtcNow.Add(trustedTime); | |
return new Invalidatable<int>(computedValue.IntegerValue, () => DateTime.UtcNow < timeoutDate); | |
} | |
// Get some value from the expensive computed value | |
public Invalidatable<int> GetDataFromExpensiveComputed() | |
{ | |
if (computed.IsInvalidated()) | |
{ | |
computed = data.GetExpensiveComputedData(); | |
} | |
// This will return an Invalidatable<int> that can be invalidated either by the time out or by the original data source no longer considering the computed data valid | |
return computed.Bind(DerivitiveCalculation); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment