IHandlerDecoration
IHandlerDecoration indicates that handler is a decoration of another handler.
/// <summary>Indicates that handler is based on decorating another <see cref="IHandlerBase"/>.</summary>
public interface IHandlerDecoration : IHandlerBase
{
/// <summary>Is decoration</summary>
bool IsHandlerDecoration { get; }
/// <summary>The underlying <see cref="IHandlerBase"/> this decoration is derivation of.</summary>
IHandlerBase? DecorationSource { get; }
}
IHandlerDecorator decorates a handler in some specific way.
/// <summary>Decorates <see cref="IHandlerBase"/> in an specific way.</summary>
public interface IHandlerDecorator
{
/// <summary>Decorate <paramref name="handler"/></summary>
/// <param name="handler"></param>
/// <returns>Decorated version of <paramref name="handler"/>. May or may not implement <see cref="IHandlerDecoration"/>.</returns>
IHandlerBase Decorate(IHandlerBase handler);
}
Decorator applies a decoration to a handler.
// Create sum calculator
Action<IQuery<(int, int), int>> sumCalculator = q => q.Response.SetValue(q.Request.Item1 + q.Request.Item2);
// Cast to handler
IHandlerBase handler = Handlers.Action(sumCalculator);
// Create decorator
IHandlerDecorator decorator = new LoggingDecorator(Console.Out);
// Decorate handler to log
handler = decorator.Decorate(handler);
// Create service
IService<(int, int), int> service = Services.CreateWithoutCache<(int, int), int>(handler);
// Query (logs with decorator)
int value = service.GetRequired((10, 20));
// The decoration prints: "(10, 20) = Entry<Object>(Value, 30, , Default)"
public class LoggingDecorator : IHandlerDecorator
{
static ConstructorT2<IHandlerBase, TextWriter, IHandlerBase> ctor = new(typeof(LoggingDecoration<,>));
TextWriter writer;
public LoggingDecorator(TextWriter writer) => this.writer = writer;
public IHandlerBase Decorate(IHandlerBase handler)
{
if (TypeUtilities.TryGetTypeArgumentOfCorrespondingDefinedType(handler.GetType(), typeof(IHandler<,>), 0, out Type requestType) &&
TypeUtilities.TryGetTypeArgumentOfCorrespondingDefinedType(handler.GetType(), typeof(IHandler<,>), 1, out Type responseType))
{
IHandlerBase decoration = ctor.Create(requestType, responseType, handler, writer);
return decoration;
}
else throw new NotSupportedException($"{handler.GetType()} is not supported.");
}
}
public class LoggingDecoration<Request, Response> : IHandler<Request, Response>, IHandlerDecoration where Request : notnull
{
public bool IsHandlerDecoration => true;
public IHandlerBase? DecorationSource => source;
IHandler<Request, Response> source;
TextWriter writer;
public LoggingDecoration(IHandlerBase source, TextWriter writer)
{
this.source = (IHandler<Request, Response>)source;
this.writer = writer;
}
public void Handle(IQuery<Request, Response> query)
{
try
{
source.Handle(query);
} finally
{
writer.WriteLine($"{query.Request} = {query.Response}");
}
}
}
Full Example
Full example
using System;
using System.IO;
using Avalanche.Service;
using Avalanche.Utilities;
public class handler_decoration
{
public static void Run()
{
{
// <01>
// Create sum calculator
Action<IQuery<(int, int), int>> sumCalculator = q => q.Response.SetValue(q.Request.Item1 + q.Request.Item2);
// Cast to handler
IHandlerBase handler = Handlers.Action(sumCalculator);
// Create decorator
IHandlerDecorator decorator = new LoggingDecorator(Console.Out);
// Decorate handler to log
handler = decorator.Decorate(handler);
// Create service
IService<(int, int), int> service = Services.CreateWithoutCache<(int, int), int>(handler);
// Query (logs with decorator)
int value = service.GetRequired((10, 20));
// The decoration prints: "(10, 20) = Entry<Object>(Value, 30, , Default)"
// </01>
}
}
// <98>
public class LoggingDecorator : IHandlerDecorator
{
static ConstructorT2<IHandlerBase, TextWriter, IHandlerBase> ctor = new(typeof(LoggingDecoration<,>));
TextWriter writer;
public LoggingDecorator(TextWriter writer) => this.writer = writer;
public IHandlerBase Decorate(IHandlerBase handler)
{
if (TypeUtilities.TryGetTypeArgumentOfCorrespondingDefinedType(handler.GetType(), typeof(IHandler<,>), 0, out Type requestType) &&
TypeUtilities.TryGetTypeArgumentOfCorrespondingDefinedType(handler.GetType(), typeof(IHandler<,>), 1, out Type responseType))
{
IHandlerBase decoration = ctor.Create(requestType, responseType, handler, writer);
return decoration;
}
else throw new NotSupportedException($"{handler.GetType()} is not supported.");
}
}
// </98>
// <99>
public class LoggingDecoration<Request, Response> : IHandler<Request, Response>, IHandlerDecoration where Request : notnull
{
public bool IsHandlerDecoration => true;
public IHandlerBase? DecorationSource => source;
IHandler<Request, Response> source;
TextWriter writer;
public LoggingDecoration(IHandlerBase source, TextWriter writer)
{
this.source = (IHandler<Request, Response>)source;
this.writer = writer;
}
public void Handle(IQuery<Request, Response> query)
{
try
{
source.Handle(query);
} finally
{
writer.WriteLine($"{query.Request} = {query.Response}");
}
}
}
// </99>
}