与#if /#endif相比,条件属性的缺点是什么?

时间:2010-08-26 18:30:53

标签: c# conditional-attribute

我的代码库有很多#if DEBUG/#endif语句,这些语句大多数都有断言类型逻辑,我不够勇于在生产中运行。

[Conditional("DEBUG")]
public void CheckFontSizeMath()
{
  //This check must not block SellSnakeOil() in production, even if it fails.
  if(perferredSize+increment!=increment+preferredSize)
    throw new WeAreInAnUnexpectedParallelUniverseException();
}

我会后悔将所有这些转变为新的做事方式吗?

UPDATE :我正在寻找两种相似但不同语法风格的特征之间的区别来做断言。我知道有一个世界上有其他方法来演示应用程序的工作,我也这样做。我还没准备好完全放弃断言。

此外,我更新了方法名称,以获得真实的仅限调试版本的方案。

4 个答案:

答案 0 :(得分:3)

这样做没有问题。目前最常用的方法是使用Code Contracts

答案 1 :(得分:2)

写测试!然后,您不必害怕您的代码正在执行您开始进行这些更改时不会发生的事情。

一旦您的代码得到测试,您就可以重构您的内容。

没有测试的代码,即使是昨天写的,也是遗留代码...... 获取Working Effectively with Legacy Code的副本,这是一本用于管理遗留代码的精彩书籍; 32条评论提供5星级。

答案 2 :(得分:1)

您拥有的其他选项是使用Hans建议的代码约定或使用System.Diagnostics.Debug命名空间中的断言方法,例如

Debug.Assert(1 + 1 == 2, "Math went wrong!");

构建发布版本时会自动删除此检查。

答案 3 :(得分:1)

缺点:

  1. 它不像独立于构建配置运行的硬检查和异常那样健壮。考虑到大多数代码应该在发布模式下处理错误这一事实是个好主意。

  2. 行为可能会因配置而异。如果你不小心,你最终可能会在条件方法中添加一些非调试逻辑或添加副作用,这样你的生产代码就无法正常工作(基本上与在C ++中意外调用ASSERT()宏内的方法相同;效果糟透了!)这里最重要的是异常。条件方法不允许您出于任何原因返回值,以便消除一个潜在的错误。但是,它们允许您抛出异常,这些异常可以显着改变发生错误情况时所采用的路径。这使得事情更难理解和维护。

  3. 在呼叫站点,调用条件方法并不明显。你只看到“DoSomething();”。我更喜欢通过约定命名我的条件方法,我知道它是有条件的;例如DEBUG_SanityCheckBufferContents()。

  4. 如果你没有#if out方法体,你的调试代码仍然存在,并且可以通过反射等方式检查/调用它。方法的IL仍然发出,呼叫站点不发出。

  5. 由于配置之间的行为不同,因此单元测试非常困难。这与第2点的行相同,但我将其作为一个单独的点添加,因为从测试的角度看它真的很糟糕。大多数开发人员将在签入之前在调试或发布中运行测试,但不是两者。我们的CI运行了两组测试,所以在通过所有测试之后检查一些内容很难找到你已经破坏了调试配置但测试通过了因为你运行了发布版本(反之亦然)。

  6. 简而言之,我的经验法则是:

    • 喜欢硬盘检查&单元测试的例外情况。在无法做到这一点的情况下使用条件方法(例如,性能关键检查)
    • 清楚地命名条件方法
    • Pragma #if out the method body in the method body
    • 非常警惕改变条件方法中的程序控制流程(我个人更喜欢Debug.Assert而不是使用条件方法时的异常,但我看到其他程序员的大量使用异常,所以这可能有争议)