2008-12-27 58 views
1

我正在写一个(非常小的)框架来检查方法的前置和后置条件。入口点是(他们可以很容易地方法,这并不重要):.Net中是否有可能仅从客户端程序集的调试版本调用某些代码?

public static class Ensures { 
    public static Validation That { 
     get { ... } 
    } 
} 

public static class Requires { 
    public static Validation That { 
     get { ... } 
    } 
} 

显然,检查后置条件可能是昂贵的,而实际上不是必要的,当方法不马车。所以,我想它的工作原理是这样的方法:

public static class Ensures { 
    [ConditionalCallingCode("DEBUG")] 
    public static Validation ThatDuringDebug { 
     get { ... } 
    } 
} 

其中ConditionalCallingCodeAttribute意味着,当调用代码,并定义了DEBUG符号编译此方法应只运行。这可能吗?

我想客户端代码看起来像这样:

public class Foo { 
    public void Bar() { 
     ... // do some work 
     Ensures.That // do these checks always 
      .IsNotNull(result) 
      .IsInRange(result, 0, 100); 

     Ensures.WhileDebuggingThat // only do these checks in debug mode 
      .IsPositive(ExpensiveCalculation(result)); 

     return result; 
    } 
} 

当然,我根本无法提供WhileDebuggingThat。随后,客户端代码应该是这样的:

public class Foo { 
    public void Bar() { 
     ... // do some work 
     Ensures.That // do these checks always 
      .IsNotNull(result) 
      .IsInRange(result, 0, 100); 

     #ifdef DEBUG 
     Ensures.That // only do these checks in debug mode 
      .IsPositive(ExpensiveCalculation(result)); 
     #endif 

     return result; 
    } 
} 

这是后备计划,如果没有别的办法了,但它打破DRY实在太差了。

据我所知,标志着WhileDebuggingThat[Conditional("DEBUG")]将发射(或不)的库的汇编,其中参考这个库中的组件的期间被定义取决于是否DEBUG此方法。所以我可以做到这一点,然后编写文档,告诉库用户将他们的代码的调试版本与库的调试版本联系起来,并发布版本与发布版本。这并不是我最好的解决方案。

最后,我可以告诉图书馆用户定义自己的项目里面这个类:

using ValidationLibrary; 
public static class EnsuresWhileDebugging { 
    [Conditional("DEBUG")] 
    public static Validation That() { 
     return Ensures.That; 
    } 
} 

我看这应该工作为好,尽量,但仍需要突破DRY原则,如果只是轻微。

+0

这不是什么断言? – 2008-12-27 13:29:17

+0

断言适用于检查后置条件(仅适用于调试版本;我希望允许在发布版本中保留后续检查),而不验证前置条件。 – 2008-12-27 14:05:24

回答

1

是在这里找到任何解决办法会比实际的要慢检查。另外,由于它不会像ConditionalAttribute那样编译到编译器中,参数仍将被计算。如果后置条件可能会非常复杂,比如

Ensures.That.IsPositive(ExpensiveCalculation(result)); 

您可以考虑使用icelava的建议,以反映调用程序集找到,如果它是建立在调试或释放 - 但你必须使用某种形式的委托人推迟计算 - 以确保只在需要时才执行。例如:

Ensures.WhileDebugging.That. IsPositive(() => ExpensiveCalculation(result)); 

IsPositive函数应该运行lambda并检查其结果,只有在反映后才能确定它是否应该计算。

3

这是否正常ConditionalAttribute不会为你做的任何事情,除了在一个属性而不是一个方法?您可能需要改变事情的调用方式,以便获取方法而不是属性 - 而且它返回值的事实可能会导致问题。

如果你能展示你的框架是如何使用的话,这将有很大的帮助 - 目前我们还没有很多工作要做。

要考虑的另一件事是提供库的各种二进制版本 - 以便调用者可以提供不实际执行任何检查的不同版本。虽然如此,只用您提供的代码很难说清楚。

0

这听起来像你正在做的大部分已经覆盖使用Debug.Assert()

对于这个问题,这个代码将永远只能在调试模式下运行(但你必须要忍受追块缓慢):

try 
{ 
    Debug.Assert(false); 
} 
catch (Exception e) 
{ 
    // will only and always run in debug mode 

} 
+0

Debug.Assert()仅适用于后置条件。如果我想要使用相同的API来验证前置和后置条件,或者轻松地在仅调试和经常检查的后置条件之间切换,则不适用。 – 2008-12-27 17:38:58

0

看来,我想要的只是不可用。我可能会承诺提供从Validationbool的隐式转换,以便可以将验证检查包装在Debug.Assert()中。

0

调试断言方法可以使用布尔程序编译即使,例如,如果该值是从一个项目的用户SETING采取设置/改变:

Debug.Assert(!Properties.Settings.Default.UseAutoDebug); 
0

我不知道,但我认为你可以使用ConditionalAttribute这个:是否发出呼叫或不发出将取决于用户的构建类型,而不是你的库。您可以使用Reflector或ILDasm来检查:编译您的示例并在Reflector(ILDasm)中查看示例项目中是否发出调用。

0

我有这种情况发生: 项目B的通话1个功能 分别包括这样的功能:。 Assembly.GetCallingAssembly()全名 如果在模式调试版本B,则运行,项目A的这个函数返回的名字,如果在模式发布版本比返回项目B的名称。 我不知道发生这种情况的原因。 请支持我 谢谢

相关问题