简体   繁体   English

与#if /#endif相比,条件属性有何缺点?

[英]What is the downside to Conditional Attributes as opposed to #if/#endif?

My code base has a lot of #if DEBUG/#endif statements that mostly have assertion type logic that I'm not brave enough to run in production. 我的代码库中有很多#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();
}

Will I regret changing all these over to the new way of doing things? 我会后悔将所有这些改变为新的工作方式吗?

UPDATE : I'm looking for the difference between characteristics of two similar but different syntax styles for doing Assertions. 更新 :我正在寻找两种类似但不同的语法样式来进行断言的特征之间的差异。 I understand there is a world of other ways to do demonstrate applications work, and I do those, too. 我知道还有很多其他方法可以演示应用程序的工作,我也可以这样做。 I'm not ready to give up Assertions altogether. 我还不准备完全放弃断言。

Also I updated the method name for a realistic debug-release-only scenario. 此外,我还更新了实际的仅调试发行版方案的方法名称。

There's no problem doing this. 这样做没有问题。 The more current approach is to use Code Contracts . 最新的方法是使用代码合同

Write tests! 编写测试! Then you don't have to be afraid that your code is doing something that you don't expect when you start making these changes. 这样一来,您不必担心代码在执行这些更改时会发生意料之外的事情。

Once you get your code under test you can refactor to your heart's content. 一旦对代码进行测试,就可以重构您内心的内容。

Code without tests, even written yesterday, is legacy code... Get a copy of Working Effectively with Legacy Code , it's an amazing book for managing legacy code; 没有测试的代码,甚至是昨天编写的代码,都是遗留代码...获得《 有效使用遗留代码》的副本,这是一本管理遗留代码的绝妙书籍; 32 reviews with 5 stars. 5星有32条评论。

Other options that you have is to either use Code Contracts as suggested by Hans or to use the assertion methods in the System.Diagnostics.Debug namespace, eg 您拥有的其他选项是使用Hans建议的代码协定,或使用System.Diagnostics.Debug命名空间中的断言方法,例如

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

This check is automatically removed when building the Release version. 构建发行版本时,将自动删除此检查。

The downsides: 缺点:

  1. It's not as robust as hard checks and exceptions that function independently of build configuration. 它不像独立于构建配置而起作用的硬检查和异常一样强大。 It's a good idea to take into account the fact that most code should handle errors in release mode. 考虑到大多数代码应在发布模式下处理错误这一事实是一个好主意。

  2. Behaviour has the potential to differ between configurations. 行为可能会因配置而异。 If you're careless, you may end up putting some non debug logic in a conditional method or adding side effects so that your production code does not function correctly (basically the same thing as accidentally calling methods inside ASSERT() macros in C++; side effects suck!) The biggest thing here is exceptions. 如果您粗心大意,可能最终会在条件方法中放入一些非调试逻辑或增加副作用,从而使生产代码无法正确运行(基本上与在C ++中意外调用ASSERT()宏中的方法相同;效果糟透了!)这里最大的事情就是例外。 Conditional methods do not allow you to return values for whatever reason so that eliminates one potential error. 条件方法不允许您出于任何原因返回值,从而消除了一个潜在的错误。 However, they do allow you to throw exceptions which can dramatically change the path taken on an error condition occurring. 但是,它们确实允许您引发异常,这些异常会极大地改变发生错误情况时采取的路径。 This makes things harder to understand and maintain. 这使事情变得更难以理解和维护。

  3. At the call site, it is not obvious that conditional methods are being called. 在调用站点,调用条件方法并不明显。 You just see "DoSomething();". 您只看到“ DoSomething();”。 I prefer to name my conditional methods via a convention where I know it's a conditional; 我更喜欢通过约定来命名条件方法,因为我知道这是一个条件。 eg DEBUG_SanityCheckBufferContents(). 例如DEBUG_SanityCheckBufferContents()。

  4. If you don't #if out the method body, your debug code will still exist and it can be inspected/invoked via reflection amongst other things. 如果不#ifout方法体,您的调试代码将仍然存在,并且可以通过反射等方法对其进行检查/调用。 The method's IL is still emitted, the call sites are not. 该方法的IL仍然会发出,而调用站点不会发出。

  5. It makes unit testing very difficult, as behaviour differs between configurations. 由于配置之间的行为不同,因此使单元测试非常困难。 This is along the same lines as point 2, but I added it as a separate point because it's really sucky from a testing perspective. 这与第2点相同,但我将其添加为单独的点,因为从测试角度来看,它确实很麻烦。 Most developers will run tests in debug or release prior to checking in, but not both. 大多数开发人员会在签入之前在调试或发行版本中运行测试,但不会两者都运行。 Our CI runs both sets of tests, so it's galling to check something in after passing all of the tests only to find you've broken the debug configuration but the tests passed because you ran the release build (or vice versa). 我们的CI会同时运行这两组测试,因此在通过所有测试后才发现某些东西是令人沮丧的,这只会发现您破坏了调试配置,但由于运行了发布版本而通过了测试(反之亦然)。

In short my rules of thumb are: 简而言之,我的经验法则是:

  • Prefer hard checks & exceptions with unit tests. 首选硬检查和例外的单元测试。 Use conditional methods where this is not possible (eg performance critical checks) 在不可能的情况下使用条件方法(例如,性能关键检查)
  • Name conditional methods clearly 明确命名条件方法
  • Pragma #if out the code in the method body 语法#如果在方法正文中列出代码
  • Be very wary of altering program control flow in conditional methods (I personally prefer Debug.Assert instead of an exception when using conditional methods, but I've seen loads of other programmers use exceptions, so this is probably up for debate) 警惕在条件方法中更改程序控制流(我个人更喜欢使用Debug.Assert而不是使用条件方法的异常,但是我看到很多其他程序员都在使用异常,因此这很可能引起争议)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM