Overriding a single interface method when closing an implementation class

This is perhaps the easiest way to explain with the help of code (this, of course, is not actual code, but it has the same properties):

I have an interface that looks something like this:

public interface ISomeProvider { object GetFoo1(); //<-- This needs caching //These others don't object GetFoo2(); object GetFoo3(); //And let say 20 more } 

And this has an implementation as follows:

  //NOTE: Sealed class otherwise we could inherit from it public sealed class SuperCleverProvider : ISomeProvider { public object GetFoo1() { return "a"; } public object GetFoo2() { return "b"; } public object GetFoo3() { return "b"; } } 

Now one of these calls, say GetFoo1 is really heavy, so I want to provide a new version of the interface where calls to it are cached using an instance of the old one.

I do it like this:

  public class CachedSuperCleverProvider : ISomeProvider { private readonly SuperCleverProvider _provider; public CachedSuperCleverProvider(SuperCleverProvider provider) { _provider = provider; } private object UsingCache<T>(string cacheKey, Func<T> eval) { //Pretend this does caching. This is not related to the question throw new NotImplementedException(); } public object GetFoo1() { return UsingCache("foo1", _provider.GetFoo1); } //The code below this point is what I want to get rid of public object GetFoo2() { return _provider.GetFoo2(); } public object GetFoo3() { return _provider.GetFoo3(); } //And so on for all the rest } 

This has two problems (at least):

  • Every time someone adds a method to the interface, I need to change this, even if I do not want this new method to be cached
  • I get this huge list of useless code that just calls the base implementation.

Can anyone think of a way to do this that doesn't have these problems?

+4
source share
2 answers

Three options:

  • Auto generate class
  • Use PostSharp or something similar to make this more interceptor based.
  • Live with him

Personally, I will probably go with the third option, unless you really do it a lot. Weigh the cost of each option - how much time are you going to spend on adding this delegation?

Personally, I would like this as a function of the language to β€œdelegate this interface through this field if I do not redefine it,” but obviously this is not present at the moment ...

+3
source

Here is what I suggest. This is not much better, but it will simplify the packaging process.

Create the SomeProviderWrapper class:

 public class SomeProviderWrapper : ISomeProvider { protected ISomeProvider WrappedProvider { get; private set; } protected SomeProviderWrapper(ISomeProvider wrapped) { if (wrapped == null) throw new ArgumentNullException("wrapped"); WrappedProvider = wrapped; } public virtual object GetFoo1() { return WrappedProvider.GetFoo1(); } public virtual object GetFoo2() { return WrappedProvider.GetFoo2(); } public virtual object GetFoo3() { return WrappedProvider.GetFoo3(); } } 

Now that the shell is assigned to its own class, you can write a caching version:

 public class CachedSuperCleverProvider : SomeProviderWrapper { public CachedSuperCleverProvider(ISomeProvider wrapped) : base(wrapped) { } private object UsingCache<T>(string cacheKey, Func<T> eval) { throw new NotImplementedException(); } public override object GetFoo1() { return UsingCache("foo1", WrappedProvider.GetFoo1); } } 

This keeps the delegation code from your super-smart provider. You will still have to maintain the delegation code, but it will not pollute the design of your caching provider.

0
source

All Articles