.Net 中是否可以仅从客户端程序集的调试版本中调用某些代码?
-
23-08-2019 - |
题
我正在编写一个(非常小的)框架来检查方法的前置条件和后置条件。入口点是(它们很容易是方法;这并不重要):
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 原则,哪怕只是稍微打破一下。
解决方案
这是在这里发现的任何解决方案将是比实际检查慢。此外,由于它不会被打造成为类的编译ConditionalAttribute
,参数仍然会被计算。如果后置条件可能是非常复杂的,如
Ensures.That.IsPositive(ExpensiveCalculation(result));
您可能会考虑使用icelava的建议,以反映调用程序集找到,如果它是建立在调试或释放 - 但你的必须的使用某种形式的委托延迟计算 - 确保在需要的时候它只是做。 e.g:
Ensures.WhileDebugging.That. IsPositive(() => ExpensiveCalculation(result));
在IsPositive函数应该运行拉姆达并检查其结果,仅反射,以找出是否应当计算之后。
其他提示
这是任何正常 ConditionalAttribute 你从一个属性,而不是方法的工作没有做,一边?你可能需要改变的东西被称为这样,你有方法,而不是属性的方式 - 而它返回的值可能会导致问题的事实。
这将有很大的帮助,如果你想展示你的框架是如何使用 - 目前我们还没有得到很多与工作
考虑将提供多种二进制的另一件事,建立资料库的 - 这样,来电者可以只提供一个不同的版本,它实际上并不做任何检查。再次,虽然,这很难说,只有您所提供的代码。
自从我要洗澡并离开家以来,我还没有尝试过这个。
- 调用 Assembly.GetCallingAssembly() 获取调用当前执行方法的方法(类)所在的程序集。
- 对该 Assembly 对象运行检查以查看它是发布版本还是调试版本.
这听起来像极了你在做什么用Debug.Assert()
已经被覆盖。
对于这个问题,这个代码将永远只能在调试模式下运行(但你必须要忍受追块缓慢):
try
{
Debug.Assert(false);
}
catch (Exception e)
{
// will only and always run in debug mode
}
看来,我要的只是不可用。我可能会沉降从Validation
提供的隐式转换到bool
,以便验证检查可以包裹在Debug.Assert()
。
在调试Assert方法可以使用程序编译即使,例如,如果值是从一个项目用户SETING截取的布尔来设置/改变:
Debug.Assert(!Properties.Settings.Default.UseAutoDebug);
我不知道,但我认为你可以使用ConditionalAttribute此:是否要发出呼叫或不发射将取决于类型的用户打造,不是你的图书馆。您可以使用反射或ILDASM检查此:编译你的样品和反射器(ILDASM)看呼叫是发出与否样本项目
我出现这种情况:项目A调用B的1函数。B 包括这个功能:assembly.getCallingAssembly()。全名如果在模式调试中构建B然后运行,则此功能返回项目A的名称,如果在模式下构建比项目B的返回名称。我不知道发生这种情况的原因。请支持我谢谢