【问题标题】:Display custom warning at compile time related to method implementation in C#在编译时显示与 C# 中的方法实现相关的自定义警告
【发布时间】:2017-03-21 08:57:24
【问题描述】:

在当前上下文中,我们有两个方法 Start 和 Stop。这两个方法是从一个函数顺序调用的。有可能一个人在他的方法中只调用了 Start() 但忘记调用 Stop()。例如

private void A()
{
  Start();

  //Buisness logic goes here

}

在这种情况下,当编译代码时,需要显示警告或错误,通知每个 Start() 都应该有一个相应的 Stop()。有人可以就如何在 C# 中实现相同的想法提出建议吗?

正确的实现方式是

private void A()
{
  Start();

  //Buisness logic goes here

  Stop();

}

【问题讨论】:

  • 听起来你应该只实现模板方法模式。或者把Start()改成Execute(Action)
  • 让这个类实现IDisposable,并在Dispose中调用Stop(或者让Start返回IDisposable而不是类本身)。对IDisposable 未在范围内进行处理有不同的检查。
  • 那么 Start 和 Stop 不可能被顺序调用,而是从不同的方法调用?

标签: c# .net


【解决方案1】:

我建议您更改您的模式以处理 StartStop 而无需将其暴露给程序员。

将实现StartStop 的类更改为实现Execute 方法,甚至不要公开StartStop

public class MyClass
{
    private void Start(){} // old public method
    private void Stop(){} // old public method

    public void Execute(Action action)
    {
         Start();
         action();
         Stop();
    }
}

用法:

var impl = new MyClass();
impl.Execute(() => {
   // do something in between start & stop
});

【讨论】:

  • 这将需要在消费者中进行大量的代码更改。应该是被动的改变。
  • 我知道这不是 OP 的要求,但如果操作引发异常,Stop() 将不会被调用。但我同意这比我的using 解决方案更难恶意规避。
  • @Sentry 好点 - 使用 try..finally 很容易修复。
【解决方案2】:

Evk 给出了一个很好的提示,下面是我将如何更详细地做到这一点:

  1. 有一个类(例如 StartStop )实现IDisposable

    public class StartStop : IDisposable
    {
        public StartStop() {  Start(); }
    
        public void Dispose() { Stop(); }
    
        protected void Start() { /*...*/ }
    
        protected void Stop() { /*...*/ }
    }
    
  2. 通过using使用这个类:

    private void A()
    {
        using( var startStopCaller = new StartStopCaller() )
        {
            // Your code here
        }
     }
    

using 将确保调用Dispose() 和随后的Stop(),除非发生硬崩溃。

【讨论】:

  • 仍然没有什么可以阻止程序员只需使用var startStop = new StartStop() 而不是在using 中,你又回到了原来的问题!
  • @Jamiec 虽然一般来说是正确的 - 许多代码检查工具会对此产生警告。
  • @Jamiec 我同意,但没有什么能阻止程序员使用反射来调用私有方法,所以总会有办法规避安全措施
  • 这将需要在消费者中进行大量的代码更改。应该是被动的改变。
  • @Prasad 我明白了。那么 Arve 的答案可能是一个更好的方法。
【解决方案3】:

这可以通过多种方式实现,主要有两个方向:

  • 如果您使用的是 .NET 平台的更高版本,因此使用的是 Roslyn 编译器 (Defaults from VS2015 and onwards),您可以考虑编写一个编译器插件来为您检查这一点。以下是一些资源:
  • 正如您得到的一些 cmets 所指出的,这可以在您的代码和程序设计中修复。 这很可能是解决这个问题的“正确”方法。一些例子:
    • 考虑implementing IDisposable 并在using statement 中使用您的类 - 但是,请记住,此处停止和处置对象可能不同。您应该根据自己对程序内部工作原理的了解做出明智的决定。
    • 如果您从其他地方调用这些类,您可以让它们实现一个包含StartStop 方法的接口。然后让调用类简单地把它们当作这个接口,并确保它调用这两个方法,无论它使用哪个实现。
    • 重新设计您的代码,使其不依赖于顺序运行 Start() 和 Stop()。这可能需要对您的程序及其工作方式进行基本的设计更改,但这可能是值得的。兼顾可读性和可维护性。

【讨论】:

  • 我们也有消费者在使用 vs 2012。也不确定在这种特殊情况下我们该如何进行。
  • 然后跳过编译器插件部分,进行代码方面的重新设计。无论 VS 版本如何,这都可以工作。
猜你喜欢
  • 2010-11-28
  • 2015-09-19
  • 1970-01-01
  • 1970-01-01
  • 2017-09-27
  • 2014-04-12
  • 1970-01-01
  • 1970-01-01
  • 2018-01-07
相关资源
最近更新 更多