Cache with false and exception capture
.ResultCaptured() decorates a provider to capture false results and thrown exceptions into IResult wrapper.
IProvider<double, double> squareProvider = Providers.Func((double x) => x * x);
IProvider<double, IResult<double>> squareResultProvider = squareProvider.ResultCaptured();
WriteLine(squareResultProvider[10].Value); // -> "100"
.ResultOpened() adapts IResult<T> back into T. Any captured exceptions are rethrown.
IProvider<double, double> squareProvider = Providers.Func((double x) => x * x);
IProvider<double, IResult<double>> squareResultProvider = squareProvider.ResultCaptured();
IProvider<double, IResult<double>> squareCachedResultProvider = squareResultProvider.Cached();
IProvider<double, double> squareCachedProvider = squareCachedResultProvider.ResultOpened();
WriteLine(squareCachedProvider[10]); // -> "100"
The combination of four providers wraps the provider to capture false results and exceptions.
IProvider<string, XDocument> docProvider =
Providers.Func<string, XDocument>(XDocument.Load)
.ResultCaptured() // Captures exception
.Cached() // ConcurrentDictionary
.ResultOpened(); // Rethrows exception
XDocument doc = docProvider["http://avalanche.fi/sitemap.xml"];
.ValueResultCaptured() and .ValueResultOpened() captures result into value-typed struct ValueResult<T> which causes less heap allocatation.
IProvider<string, XDocument> docProvider =
Providers.Func<string, XDocument>(XDocument.Load)
.ValueResultCaptured() // Captures exception
.Cached() // ConcurrentDictionary
.ValueResultOpened(); // Rethrows exception
XDocument doc = docProvider["http://avalanche.fi/sitemap.xml"];
.InvalidateCache(deep) proceeds invalidation through decoration stack when deep: true.
// Integer printer, cached
IProvider<int, string> intPrinter =
Providers.Func<int, string>(i => i.ToString())
.ResultCaptured() // Captures exception
.Cached() // ConcurrentDictionary
.ResultOpened(); // Rethrows exception
// Print integers to strings
string print1 = intPrinter[10];
string print2 = intPrinter[10];
// Compare object reference
WriteLine(object.ReferenceEquals(print1, print2)); // "True"
// Invalidate cache
intPrinter.InvalidateCache(deep: true);
// Compare object reference
WriteLine(object.ReferenceEquals(print1, intPrinter[10])); // "False"
Result
IResult is the interface for types that hold result values and exceptions.
/// <summary>Evaluation result</summary>
public interface IResult
{
/// <summary>Evaluation status</summary>
ResultStatus Status { get; set; }
/// <summary>Result value</summary>
object? Value { get; set; }
/// <summary>Error object</summary>
Exception? Error { get; set; }
/// <summary>(optional) Request that was used to create this result</summary>
object? Request { get; set; }
}
/// <summary>Evaluation status </summary>
public enum ResultStatus : int
{
/// <summary>No evaluation</summary>
Unassigned = 0,
/// <summary>Resulted to no value</summary>
NoResult = 1,
/// <summary>Resulted to successful value</summary>
Ok = 2,
/// <summary>Resulted to error</summary>
Error = 3,
}
IResult<T> is same with type generics.
/// <summary>Evaluation result</summary>
public interface IResult<T> : IResult
{
/// <summary>Result value, valid only if <see cref="ResultStatus.Ok"/></summary>
new T Value { get; set; }
}
IResult.Error contains captured exception.
IResult<double> result = squareResultProvider[double.NaN];
WriteLine(result.Error); // -> "ArgumentException"
.AssertValue<T>() returns value or rethrows captured exception.
IResult<double> result_ = squareResultProvider[10];
WriteLine(squareResultProvider[10].AssertValue<IResult<double>, double>()); // -> "100"
WriteLine(squareResultProvider[double.NaN].AssertValue<IResult<double>, double>()); // -> "100"
ResultProvider
ResultProviderBase<Key, Value> can be used as base implementation for providers that capture exceptions right into IResult.
public class SquareResultProvider : ResultProviderBase<double, double>
{
protected override bool TryGetValue(double x, out double value)
{
// NaN
if (double.IsNaN(x)) throw new ArgumentException("NaN");
// Infinity
if (double.IsInfinity(x)) throw new ArgumentException("Infinity");
// Assign value
value = x * x;
// Return
return true;
}
}
IProvider<double, IResult<double>> squareResultProvider = new SquareResultProvider();
WriteLine(squareResultProvider[10].Value); // -> "100"
Full Example
Full example
using System;
using System.Xml.Linq;
using Avalanche.Utilities.Provider;
using static System.Console;
class provider_result
{
public static void Run()
{
{
// <01>
IProvider<double, double> squareProvider = Providers.Func((double x) => x * x);
IProvider<double, IResult<double>> squareResultProvider = squareProvider.ResultCaptured();
WriteLine(squareResultProvider[10].Value); // -> "100"
// </01>
}
{
// <02>
IProvider<double, double> squareProvider = Providers.Func((double x) => x * x);
IProvider<double, IResult<double>> squareResultProvider = squareProvider.ResultCaptured();
IProvider<double, IResult<double>> squareCachedResultProvider = squareResultProvider.Cached();
IProvider<double, double> squareCachedProvider = squareCachedResultProvider.ResultOpened();
WriteLine(squareCachedProvider[10]); // -> "100"
// </02>
}
{
// <03>
IProvider<string, XDocument> docProvider =
Providers.Func<string, XDocument>(XDocument.Load)
.ResultCaptured() // Captures exception
.Cached() // ConcurrentDictionary
.ResultOpened(); // Rethrows exception
XDocument doc = docProvider["http://avalanche.fi/sitemap.xml"];
// </03>
}
{
// <04>
IProvider<string, XDocument> docProvider =
Providers.Func<string, XDocument>(XDocument.Load)
.ValueResultCaptured() // Captures exception
.Cached() // ConcurrentDictionary
.ValueResultOpened(); // Rethrows exception
XDocument doc = docProvider["http://avalanche.fi/sitemap.xml"];
// </04>
}
{
// <10>
// Integer printer, cached
IProvider<int, string> intPrinter =
Providers.Func<int, string>(i => i.ToString())
.ResultCaptured() // Captures exception
.Cached() // ConcurrentDictionary
.ResultOpened(); // Rethrows exception
// Print integers to strings
string print1 = intPrinter[10];
string print2 = intPrinter[10];
// Compare object reference
WriteLine(object.ReferenceEquals(print1, print2)); // "True"
// Invalidate cache
intPrinter.InvalidateCache(deep: true);
// Compare object reference
WriteLine(object.ReferenceEquals(print1, intPrinter[10])); // "False"
// </10>
}
{
try
{
// <20B>
IProvider<double, IResult<double>> squareResultProvider = new SquareResultProvider();
WriteLine(squareResultProvider[10].Value); // -> "100"
// </20B>
// <20C>
IResult<double> result = squareResultProvider[double.NaN];
WriteLine(result.Error); // -> "ArgumentException"
// </20C>
// <20D>
IResult<double> result_ = squareResultProvider[10];
WriteLine(squareResultProvider[10].AssertValue<IResult<double>, double>()); // -> "100"
WriteLine(squareResultProvider[double.NaN].AssertValue<IResult<double>, double>()); // -> "100"
// </20D>
}
catch (Exception) { }
}
}
// <20>
public class SquareResultProvider : ResultProviderBase<double, double>
{
protected override bool TryGetValue(double x, out double value)
{
// NaN
if (double.IsNaN(x)) throw new ArgumentException("NaN");
// Infinity
if (double.IsInfinity(x)) throw new ArgumentException("Infinity");
// Assign value
value = x * x;
// Return
return true;
}
}
// </20>
}