I am working with legacy code, and converting single-instance implementations into multiple instance.
The basic example below illustrates what I am doing -
- Creating a object that wraps each call of an interface with a disposable mutex (to give a nice using{...} block), and
- passing an instance of an object that uses the interface into an instance of the wrapper object.
code here:
// An Interface
public interface IImplementation
{
void DoSomething();
double MeasureSomething();
}
// An implementation
public class Implementation : IImplementation
{
private int iparam;
private string sparam;
public Implementation(string sparam, int iparam)
{
this.sparam = sparam;
this.iparam = iparam;
}
public void DoSomething()
{
//actually do something here
}
public double MeasureSomething()
{
double value = 0.0;
//actually measure something here
return value;
}
}
// a disposable safety wrap object
public class SafetyWrap : IDisposable
{
public SafetyWrap(string resource)
{
mutex = new Mutex(false, resource);
try
{
if (mutex.WaitOne(Timeout.Infinite) == false)
throw new TimeoutException("Timed out trying to acquire lock");
}
catch (AbandonedMutexException)
{
// Log "Caught abandoned mutex"
}
}
private Mutex mutex;
#region IDisposable Members
private bool disposed = false;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
mutex.ReleaseMutex();
mutex.Close();
}
disposed = true;
}
}
~SafetyWrap()
{
Dispose(false);
}
#endregion IDisposable Members
}
// a wrapper class to protect the object
public class WrappedImplementation : IImplementation
{
private IImplementation objectToWrap;
private string mySafetyString;
public WrappedImplementation(IImplementation objectToWrap)
{
this.objectToWrap = objectToWrap;
mySafetyString = "GeneratedToPreventConflicts";
}
#region IImplmentation Members
public void DoSomething()
{
using (new SafetyWrap(mySafetyString))
{
objectToWrap.DoSomething();
}
}
public double MeasureSomething()
{
using (new SafetyWrap(mySafetyString))
{
return objectToWrap.MeasureSomething();
}
}
#endregion IImplmentation Members
}
internal class Program
{
private static void Main(string[] args)
{
IImplementation normalObject = new Implementation("dummy", 1);
IImplementation safeObject = new WrappedImplementation(normalObject);
}
}
This however involves creating a lot of boilerplate (I have in, actual fact, many interfaces to implement) and it still doesn't guarantee that they can and/or will be used everywhere that they could/should.
Is there a better alternative way to achieve this aim?
You could generate the code.
For this, I believe a quite small generator code will do the task. You can fetch the interface members for which you want to generate wrappers and generate the code for the wrappers by a design-time T4-template. This way, you avoid duplicate concepts and can easily change all the implementation if you just alter the template from which the code was generated.
The downside of this approach is that the IntelliSense support and the default editor built into Visual Studio for T4 templates currently is very poor (actually for a long time, even).