Expression Example
This example demostrates how expression processing can be broken down into smaller and simpler handlers.
The Expression classes in this example.
/// <summary>Expression</summary>
public record Expression() : IRecord;
/// <summary>Binary operation expression</summary>
public record BinaryExpression([Request] object operation, [Request] object left, [Request] object right) : Expression;
/// <summary>Constant expression</summary>
public record ConstantExpression([Request] object value) : Expression;
Evaluate
EvaluateRequest is request to evaluate the value of an Expression.
/// <summary>Request to evaluate expression</summary>
public record struct EvaluateRequest([Request] object Expression) : IRequestFor<object>
{
/// <summary>Create from <paramref name="expression"/></summary>
public static implicit operator EvaluateRequest(Expression expression) => new EvaluateRequest(expression);
}
Each handler provides a simple service, and together they can resolve trees of expressions.
/// <summary>Evaluates sum-expressions of integers.</summary>
[Order(100), Export<IHandlerBase>]
public class SumEvaluator : IHandler<EvaluateRequest, int>
{
/// <summary>Evaluate sum expression.</summary>
public void Handle(IQuery<EvaluateRequest, int> query)
{
// Query already handled by another handler
if (query.Handled()) return;
// Not Binary Expression
if (query.Request.Expression is not BinaryExpression e) return;
// Operation not "+"
if (e.operation is not string op || op != "+") return;
// Evaluate left
if (!query.Service.TryGet(new EvaluateRequest(e.left), out int? lv)) return;
// Evaluate right
if (!query.Service.TryGet(new EvaluateRequest(e.right), out int? rv)) return;
// Calculate sum
int sum = lv!.Value + rv!.Value;
// Assign result
query.Response.SetValue(sum);
}
}
/// <summary>Evaluates constant expressions.</summary>
[Order(1_000), Export<IHandlerBase>]
public class ConstantEvaluator : IHandler<EvaluateRequest, int>
{
/// <summary>Evaluate sum expression.</summary>
public void Handle(IQuery<EvaluateRequest, int> query)
{
// Query already handled by another handler
if (query.Handled()) return;
// Not constant
if (query.Request.Expression is not ConstantExpression ce) return;
// Assign constant
query.Response.SetValue(ce.value);
}
}
Evaluate value of expression.
// Find exported handlers
IHandlerBase[] handlers = HandlerExports.Of<Anchor>();
// Create service
IService service = Services.Create((handlers, ServiceHandlers.Instance));
// Type-cast
IService<EvaluateRequest, int> evaluateService = service.Cast<EvaluateRequest, int>();
// Create expression: (6+2)+100
Expression e =
new BinaryExpression("+",
new BinaryExpression("+",
new ConstantExpression(6),
new ConstantExpression(2)),
new ConstantExpression(100));
// Evaluate value
int value = evaluateService.GetRequired(e);
// Print value
WriteLine(value); // "108"
Coalesce
CoalesceRequest is similiar request, but it tries to optimize expressions into smaller form.
/// <summary>Request to coalesce expression into shorter format</summary>
public record struct CoalesceRequest([Request] object Expression) : IRequestFor<Expression>
{
/// <summary>Create from <paramref name="expression"/></summary>
public static implicit operator CoalesceRequest(Expression expression) => new CoalesceRequest(expression);
}
Each handler does their own part, and together they handle expression trees.
/// <summary>Coalesces sum expessions.</summary>
[Order(10), Export<IHandlerBase>]
public class SumCoalescer : IHandler<CoalesceRequest, Expression>
{
/// <summary>Evaluate sum expression.</summary>
public void Handle(IQuery<CoalesceRequest, Expression> query)
{
// Query already handled by another handler
if (query.Handled()) return;
// Not Binary Expression
if (query.Request.Expression is not BinaryExpression e) return;
// Not "+" operation
if (e.operation is not string op || op != "+") return;
// Get child expressions
object? le = e.left, re = e.right;
// Try resolve left
if (le is not ConstantExpression) query.Service.TryGet(new CoalesceRequest(le), out le);
// Left is not constant
if (le is not ConstantExpression lc || lc.value is not int lv) return;
// Try resolve right
if (re is not ConstantExpression) query.Service.TryGet(new CoalesceRequest(re), out re);
// Right is not constant
if (re is not ConstantExpression rc || rc.value is not int rv) return;
// Calculate sum
int sum = lv + rv;
// Replace as constant
ConstantExpression result = new ConstantExpression(sum);
// Assign result
query.Response.SetValue(result);
}
}
/// <summary>Return expression as is.</summary>
[Order(1_000_000_000), Export<IHandlerBase>]
public class PassthroughCoaleser : IHandler<CoalesceRequest, Expression>
{
/// <summary>Evaluate sum expression.</summary>
public void Handle(IQuery<CoalesceRequest, Expression> query)
{
// Query already handled by another handler
if (query.Handled()) return;
// As-is
query.Response.SetValue(query.Request.Expression);
}
}
Coalesce expression.
// Find exported handlers
IHandlerBase[] handlers = HandlerExports.Of<Anchor>();
// Create service
IService service = Services.Create((handlers, ServiceHandlers.Instance));
// Type-cast
IService<CoalesceRequest, Expression> coalesceService = service.Cast<CoalesceRequest, Expression>();
// Create expression: (6+2)+100
Expression e =
new BinaryExpression("+",
new BinaryExpression("+",
new ConstantExpression(6),
new ConstantExpression(2)),
new ConstantExpression(100));
// Coalese expression into shorter format
Expression ce = coalesceService.GetRequired(e);
// Print expression
WriteLine(ce); // "ConstantExpression { value = 108 }"
Full Example
Full example
using System;
using Avalanche.Module;
using Avalanche.Service;
using Avalanche.Utilities;
using Avalanche.Utilities.Record;
using static System.Console;
public class example_expression
{
// <01>
/// <summary>Expression</summary>
public record Expression() : IRecord;
/// <summary>Binary operation expression</summary>
public record BinaryExpression([Request] object operation, [Request] object left, [Request] object right) : Expression;
/// <summary>Constant expression</summary>
public record ConstantExpression([Request] object value) : Expression;
// </01>
public static void Run()
{
{
// <10>
// Find exported handlers
IHandlerBase[] handlers = HandlerExports.Of<Anchor>();
// Create service
IService service = Services.Create((handlers, ServiceHandlers.Instance));
// Type-cast
IService<EvaluateRequest, int> evaluateService = service.Cast<EvaluateRequest, int>();
// Create expression: (6+2)+100
Expression e =
new BinaryExpression("+",
new BinaryExpression("+",
new ConstantExpression(6),
new ConstantExpression(2)),
new ConstantExpression(100));
// Evaluate value
int value = evaluateService.GetRequired(e);
// Print value
WriteLine(value); // "108"
// </10>
}
{
// <20>
// Find exported handlers
IHandlerBase[] handlers = HandlerExports.Of<Anchor>();
// Create service
IService service = Services.Create((handlers, ServiceHandlers.Instance));
// Type-cast
IService<CoalesceRequest, Expression> coalesceService = service.Cast<CoalesceRequest, Expression>();
// Create expression: (6+2)+100
Expression e =
new BinaryExpression("+",
new BinaryExpression("+",
new ConstantExpression(6),
new ConstantExpression(2)),
new ConstantExpression(100));
// Coalese expression into shorter format
Expression ce = coalesceService.GetRequired(e);
// Print expression
WriteLine(ce); // "ConstantExpression { value = 108 }"
// </20>
}
}
// <11>
/// <summary>Request to evaluate expression</summary>
public record struct EvaluateRequest([Request] object Expression) : IRequestFor<object>
{
/// <summary>Create from <paramref name="expression"/></summary>
public static implicit operator EvaluateRequest(Expression expression) => new EvaluateRequest(expression);
}
// </11>
// <12>
/// <summary>Evaluates sum-expressions of integers.</summary>
[Order(100), Export<IHandlerBase>]
public class SumEvaluator : IHandler<EvaluateRequest, int>
{
/// <summary>Evaluate sum expression.</summary>
public void Handle(IQuery<EvaluateRequest, int> query)
{
// Query already handled by another handler
if (query.Handled()) return;
// Not Binary Expression
if (query.Request.Expression is not BinaryExpression e) return;
// Operation not "+"
if (e.operation is not string op || op != "+") return;
// Evaluate left
if (!query.Service.TryGet(new EvaluateRequest(e.left), out int? lv)) return;
// Evaluate right
if (!query.Service.TryGet(new EvaluateRequest(e.right), out int? rv)) return;
// Calculate sum
int sum = lv!.Value + rv!.Value;
// Assign result
query.Response.SetValue(sum);
}
}
/// <summary>Evaluates constant expressions.</summary>
[Order(1_000), Export<IHandlerBase>]
public class ConstantEvaluator : IHandler<EvaluateRequest, int>
{
/// <summary>Evaluate sum expression.</summary>
public void Handle(IQuery<EvaluateRequest, int> query)
{
// Query already handled by another handler
if (query.Handled()) return;
// Not constant
if (query.Request.Expression is not ConstantExpression ce) return;
// Assign constant
query.Response.SetValue(ce.value);
}
}
// </12>
// <21>
/// <summary>Request to coalesce expression into shorter format</summary>
public record struct CoalesceRequest([Request] object Expression) : IRequestFor<Expression>
{
/// <summary>Create from <paramref name="expression"/></summary>
public static implicit operator CoalesceRequest(Expression expression) => new CoalesceRequest(expression);
}
// </21>
// <22>
/// <summary>Coalesces sum expessions.</summary>
[Order(10), Export<IHandlerBase>]
public class SumCoalescer : IHandler<CoalesceRequest, Expression>
{
/// <summary>Evaluate sum expression.</summary>
public void Handle(IQuery<CoalesceRequest, Expression> query)
{
// Query already handled by another handler
if (query.Handled()) return;
// Not Binary Expression
if (query.Request.Expression is not BinaryExpression e) return;
// Not "+" operation
if (e.operation is not string op || op != "+") return;
// Get child expressions
object? le = e.left, re = e.right;
// Try resolve left
if (le is not ConstantExpression) query.Service.TryGet(new CoalesceRequest(le), out le);
// Left is not constant
if (le is not ConstantExpression lc || lc.value is not int lv) return;
// Try resolve right
if (re is not ConstantExpression) query.Service.TryGet(new CoalesceRequest(re), out re);
// Right is not constant
if (re is not ConstantExpression rc || rc.value is not int rv) return;
// Calculate sum
int sum = lv + rv;
// Replace as constant
ConstantExpression result = new ConstantExpression(sum);
// Assign result
query.Response.SetValue(result);
}
}
/// <summary>Return expression as is.</summary>
[Order(1_000_000_000), Export<IHandlerBase>]
public class PassthroughCoaleser : IHandler<CoalesceRequest, Expression>
{
/// <summary>Evaluate sum expression.</summary>
public void Handle(IQuery<CoalesceRequest, Expression> query)
{
// Query already handled by another handler
if (query.Handled()) return;
// As-is
query.Response.SetValue(query.Request.Expression);
}
}
// </22>
/// <summary>Dummy class that is used to get reference to the Assembly.</summary>
public class Anchor { }
}