I have this code:
abstract class CommunicationChannel<Client> : IDisposable where Client : class, IDisposable {
protected Client client;
public void Open() {
try
{
client = CreateClient();
}
catch (Exception)
{
client.Dispose();
throw;
}
}
public virtual void Dispose() {
client.Dispose();
}
private Client CreateClient()
{
return Activator.CreateInstance<Client>();
}
}
class Communicator : CommunicationChannel<Client>
{
// here I have specific methods
void Method1(args) {
Open();
try {
client.Method1(args);
}
catch(Exception) {
// Cleanup
}
}
// this is getting too verbose already
void Method2(args) {
Open();
try {
client.Method2(args);
}
catch(Exception) {
// Cleanup
}
}
}
class Client: IDisposable {
public void Dispose()
{
}
}
I would want in the base class CommunicationChannel to be able to intercept somehow all the calls related to client and handle the exceptions before propagating them to the derived class CommunicationChannel. The generic parameter of the base class can contain different methods (in my example we only have Method 1)
I would ideally want a solution in which I don't have to call CommunicationChannel.CallMethod("Method1", args).
You could make client private and force subclasses to access it in a Func or Action. You can then add you before/after logic:
abstract class CommunicationChannel<Client> : IDisposable where Client : class, IDisposable
{
private Client client;
protected TResult WithClient<TResult>(Func<Client, TResult> f)
{
this.Open();
try
{
return f(client);
}
catch (Exception)
{
//cleanup
}
return default(TResult);
}
protected void WithClient(Action<Client> act)
{
WithClient<object>(c => { act(c); return null; })
}
}
your subclasses can then do:
class Communicator : CommunicationChannel<Client>
{
bool Method1(args)
{
return WithClient<bool>(c => { return c.Method1(args); });
}
}
I think this is a good case to use AOP (Aspect Oriented Programming).
What you could do is set up an aspect which OnEntry, executes the Open method and catches the exceptions with the OnException method.
Then all you have to do is decorate the methods you want to use that aspect on with an Attribute
Ill demonstrate what i mean using PostSharp:
public class CommunicationAspect : OnMethodBoundaryAspect
{
public override void OnEntry(MethodExecutionArgs args)
{
var communicationObject = args.Instance as CommunicationObject;
communicationObject.Open();
args.FlowBehavior = FlowBehavior.Continue;
}
public override void OnException(MethodExecutionArgs args)
{
_logger.log(string.Format("Exception {0} has occured on method {1}", args.Exception, args.Method.Name));
}
}
Then, decorate your methods with this attribute:
class Communicator : CommunicationChannel<Client>
{
[CommunicationAspect]
void Method1(args)
{
client.Method1(args);
}
[CommunicationAspect]
void Method2(args)
{
client.Method2(args);
}
}
PostSharp is a great framework that makes it really easy to get started, I suggest you look into it.
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