Let's say I have this structure of classes and interfaces:
interface IService {}
interface IEmailService : IService
{
Task SendAsync(IMessage message);
}
class EmailService : IEmailService
{
async Task SendAsync(IMessage message)
{
await ...
}
}
interface ICircuitBreaker<TService> : IService where TService : IService
{
TService Service { get; set; }
Task<IResult> PerformAsync(Func<Task<Iresult>> func);
}
class EmailServiceCircuitBreaker : ICircuitBreaker<IEmailService>
{
IEmailService Service { get; set; }
public EmailServiceCircuitBreaker(IEmailService service)
{
Service = service;
}
public async Task<IResult> PerformAsync(Func<Task<Iresult>> func)
{
try
{
func();
}
catch(Exception e){//Handle failure}
}
}
So now I'd like to change EmailServiceCircuitBreaker
to:
class EmailServiceCircuitBreaker : ICircuitBreaker<IEmailService>, IEmailService
so I can wrap every method from IEmailService
and Send(...)
will look like:
async Task<IResult> IEmailService.SendAsync(IMessage m)
=> await PerformAsync(async () => await Service.SendAsync(m));
And in controller I can use it as IEmailService
even if this is ICircuitBreaker<IEmailService>
without knowing that.
But, if any of my colleagues will implement ICircuitBreaker<T>
I'd like to force his class to also implement T
When you wan't to have a new language constraint, then you can throw custom errors while compilation
You can create a Code Analysis as below, use DiagnosticAnalyzer
https://johnkoerner.com/csharp/creating-your-first-code-analyzer/
Using DiagnosticAnalyzer
, you can search for the pattern and throw exception
context.RegisterSymbolAction(AnalyzeSymbol, SymbolKind.NamedType);
private static void AnalyzeSymbol(SyntaxNodeAnalysisContext context)
{
var node = (ObjectCreationExpressionSyntax)context.Node;
if (node != null && node.Type != null && node.Type is IdentifierNameSyntax)
{
var type = (IdentifierNameSyntax)node.Type;
var symbol = (INamedTypeSymbol)context.SemanticModel.GetSymbolInfo(type).Symbol;
var isIService = IsInheritedFromIService(symbol);
if (isIService )
{
... //Check you logic
context.ReportDiagnostic(diagnostic);
}
}
}
private static bool IsInheritedFromIService(ITypeSymbol symbol)
{
bool isIService = false;
var lastParent = symbol;
if (lastParent != null)
{
while (lastParent.BaseType != null)
{
if (lastParent.BaseType.Name == "IService")
{
isIService = true;
lastParent = lastParent.BaseType;
break;
}
else
{
lastParent = lastParent.BaseType;
}
}
}
return isIService ;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With