密封实现类时覆盖单个接口方法

时间:2011-08-19 09:21:29

标签: c# interface sealed

这可能是最容易用代码解释的(这当然不是实际代码,但它具有相同的属性):

我的界面看起来像这样:

    public interface ISomeProvider
    {
        object GetFoo1(); //<-- This needs caching

        //These others don't
        object GetFoo2();
        object GetFoo3();

        //And let's say 20 more
    }

这有一个像这样的实现:

    //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";
        }
    }

现在其中一个调用,让我们说GetFoo1真的很重,所以我想提供一个新版本的接口,其中使用旧版本的实例缓存对它的调用。

我现在这样做:

    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
    }

这有两个问题(至少):

  • 每当有人向界面添加方法时,我都要改变它,即使我不希望这个新方法被缓存
  • 我得到了这个庞大的无用代码列表,只需调用底层实现。

有人能想到一种没有这些问题的方法吗?

2 个答案:

答案 0 :(得分:3)

三个选项:

  • 自动生成课程
  • 使用PostSharp或类似的方法以更多基于拦截器的方式执行此操作
  • 和它一起生活

我个人可能会选择第三个选项,除非你真的发现自己这么做了。权衡每个选项的成本 - 您实际花费多少时间来添加此委托?

我个人喜欢将这种东西视为一种语言特征 - “除非我覆盖它,否则通过这个字段委托给这个界面”,但显然目前还不存在......

答案 1 :(得分:0)

这是我的建议。它并没有太好,但会简化包装过程。

创建课程SomeProviderWrapper

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();
    }
}

现在将包装降级为自己的类,您可以编写缓存版本:

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);
    }
}

这使委托代码不会超出您的超级聪明的提供程序。您仍然需要维护委托代码,但它不会污染您的缓存提供程序的设计。