【问题标题】:Is there an elegant way to make every method in a class start with a certain block of code in C#?有没有一种优雅的方法可以让类中的每个方法都以 C# 中的某个代码块开头?
【发布时间】:2016-03-11 03:30:16
【问题描述】:

我有一个类,其中每个方法都以相同的方式开始:

internal class Foo {
  public void Bar() {
    if (!FooIsEnabled) return;
    //...
  }
  public void Baz() {
    if (!FooIsEnabled) return;
    //...
  }
  public void Bat() {
    if (!FooIsEnabled) return;
    //...
  }
}

有没有一种很好的方法来要求(希望不要每次都写)类中每个公共方法的FooIsEnabled 部分?

我检查了Is there an elegant way to make every method in a class start with a certain block of code?,但这个问题是针对 Java 的,它的答案是使用 Java 库。

【问题讨论】:

  • 你可以在运行时使用 DynamicProxy 之类的东西来编织它。
  • 答案与 Java 单方面编程(例如 PostSharp)或动态代理几乎相同。或者当然,代码生成——只需制作一个简单的 T4 模板,在编译时生成代理。
  • 甚至还有 Fody 作为替代方案...编译后修改程序集。请注意,.NET 没有语言内 java.lang.reflect.Proxy
  • 现在更重要的是,您为什么要这样做以及采用哪种解决方案?您正在使用的平台中可能有内置解决方案。
  • 您可能需要考虑多态解决方案。提取一个通用接口并提供两个实现:一个 (Foo) 执行函数中的代码,另一个 (FooDisabled) 仅提供没有主体的虚拟方法实现。然后,您可以在特定情况下实例化您需要的那个。

标签: c#


【解决方案1】:

您正在寻找的主体是来自Aspect Oriented Programming 或AOP 域的拦截。

虽然 C# 不直接支持它,但有一些可靠的选择:

  1. Postsharp
  2. Unity Interception
  3. Spring.NET
  4. Castle Interceptors

如果我明天有时间,我会为你做一个例子......

【讨论】:

【解决方案2】:

我认为您无法轻松摆脱 Bar、Baz、Bat 方法中多余的混乱,但您可以通过创建一个方法来执行您传入的操作,从而使其更易于管理。

internal class Foo
{
    private bool FooIsEnabled;

    public void Bar()
    {
        Execute(() => Debug.WriteLine("Bar"));
    }

    public void Baz()
    {
        Execute(() => Debug.WriteLine("Baz"));
    }

    public void Bat()
    {
        Execute(() => Debug.WriteLine("Bat"));
    }

    public void Execute(Action operation)
    {
        if (operation == null)
            throw new ArgumentNullException("operation");

        if (!FooIsEnabled)
            return;

        operation.Invoke();
    }
}

【讨论】:

    【解决方案3】:

    当然:

    internal interface IFoo {
        void Bar();
        void Baz();
        void Bat();
    }
    
    internal class Foo {
        private IFoo FooImplementation = new DisabledFoo() // or new EnabledFoor()
    
        public bool FooIsEnabled
        {
            get
            {
                return FooImplementation is EnabledFoo;
            }
            set
            {
                FooImplementation = value ? new EnabledFoo() : new DisabledFoo()
            }
        }
    
        public void Bar() {
            FooImplementation.Bar();
        }
        public void Baz() {
            FooImplementation.Baz();
        }
        public void Bat() {
            FooImplementation.Bat();        
        }
    }
    
    internal class EnabledFoo : IFoo {
        public void Bar() {
            //...
        }
        public void Baz() {
            //...
        }
        public void Bat() {
            //...
        }
    }
    
    internal class DisabledFoo : IFoo {
        public void Bar() {}
        public void Baz() {}
        public void Bat() {}
    }
    

    如果您的意图是模拟 foo 实现以进行单元测试,只需删除 FooIsEnabled 属性并将 FooImplementation 公开。在这种情况下,您还应该摆脱DisabledFoo,并使用以下实例进行测试:

    var fooImplementationMock = new Mock<IFoo>();
    var foo = new Foo { FooImplementation = fooImplementationMock.Object };
    foo.Bar();
    fooImplementationMock.Verify(f => f.Bar());
    

    假设您使用的是moq

    【讨论】:

      猜你喜欢
      • 2010-12-10
      • 2010-11-23
      • 2021-08-14
      • 2014-12-19
      • 1970-01-01
      • 1970-01-01
      • 2014-04-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多