我正在编写一个(非常小的)框架来检查方法的前后条件。切入点是(它们可以很容易地成为方法;这无关紧要):
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 :(得分:3)
除了处理属性而不是方法之外,这是普通的ConditionalAttribute不能为你做什么吗?您可能需要更改事物的调用方式,以便您拥有方法而不是属性 - 而且它返回值的事实可能会导致问题。
如果您展示了如何使用框架,那将会有很大帮助 - 目前我们还没有很多工作要做。
要考虑的另一件事是提供库的各种二进制版本 - 以便调用者可以提供不实际执行任何检查的不同版本。尽管如此,仅用你提供的代码很难说清楚。
答案 1 :(得分:1)
此处找到的任何解决方案都会比实际检查慢。此外,由于它不会像ConditionalAttribute
那样构建到编译器中,因此仍然会计算参数。如果后置条件可能非常复杂,例如
Ensures.That.IsPositive(ExpensiveCalculation(result));
您可以考虑使用icelava的建议来反思调用程序集以查找它是在调试版本还是发布版本中 - 但是必须使用某种代理来延迟计算 - 以确保它只在需要时才完成。 e.g:
Ensures.WhileDebugging.That. IsPositive(() => ExpensiveCalculation(result));
IsPositive函数应该运行lambda并检查其结果,只有在反映之后才能确定是否应该计算它。
答案 2 :(得分:0)
我没有尝试这个,因为我要洗澡离开家。
答案 3 :(得分:0)
听起来你正在做的大部分事情已经被Debug.Assert()
覆盖了。
就此而言,这段代码只会在调试模式下运行(但你必须忍受catch-block的缓慢):
try
{
Debug.Assert(false);
}
catch (Exception e)
{
// will only and always run in debug mode
}
答案 4 :(得分:0)
看来我想要的东西是不可用的。我可能会考虑提供从Validation
到bool
的隐式转换,以便验证检查可以包含在Debug.Assert()
中。
答案 5 :(得分:0)
即使在编译程序之后,也可以使用bool设置/更改Debug Assert方法,例如,如果值来自项目用户设置:
Debug.Assert(!Properties.Settings.Default.UseAutoDebug);
答案 6 :(得分:0)
我不确定,但我认为您可以使用ConditionalAttribute:是否发出调用或不发送将取决于用户的构建类型,而不是您的库。您可以使用Reflector或ILDasm进行检查:编译样本并在Reflector(ILDasm)中查看示例项目中是否发出调用。
答案 7 :(得分:0)
我发生了这种情况: 项目A调用B的1项功能。 B包括这个功能: Assembly.GetCallingAssembly()。全名 如果构建B在模式调试然后运行,则此函数返回项目A的名称,如果在模式发布时构建,则返回项目B的返回名称。 我不知道发生这种情况的原因。 请支持我 感谢