【问题标题】:Is it possible in .Net to call some code only from debug builds of client assemblies?.Net 中是否可以仅从客户端程序集的调试版本中调用某些代码?
【发布时间】:2010-09-28 12:55:05
【问题描述】:

我正在编写一个(非常小的)框架来检查方法的前置条件和后置条件。入口点是(它们很容易成为方法;没关系):

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。

据我了解,用[Conditional("DEBUG")] 标记WhileDebuggingThat 将发出(或不发出)此方法,具体取决于在库编译期间是否定义了DEBUG,不是引用的程序集这个图书馆。所以我可以这样做,然后编写文档告诉库用户将其代码的调试版本与库的调试版本链接起来,并将发布版本与发布版本联系起来。我觉得这并不是最好的解决方案。

最后,我可以告诉图书馆用户在他们的项目中定义这个类:

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

据我所知,这应该也可以,但仍然需要打破 DRY 原则,即使只是轻微的。

【问题讨论】:

  • 这不就是断言的用途吗?
  • 断言用于检查后置条件(并且仅在调试版本中;我也希望允许在发布版本中保留后置条件检查),而不是验证前置条件。

标签: c# build debugging release conditional-compilation


【解决方案1】:

除了处理属性而不是方法之外,这是不是普通的ConditionalAttribute 不能为您做的事情?您可能需要更改调用方式,以便获得方法而不是属性 - 它返回值的事实可能会导致问题。

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

要考虑的另一件事是提供库的各种二进制版本——这样调用者就可以提供一个不同的版本,而实际上并不做任何检查。但是,仅凭您提供的代码很难判断。

【讨论】:

    【解决方案2】:

    在此处找到的任何解决方案都会比实际检查慢。此外,由于它不会像ConditionalAttribute 那样内置到编译器中,因此仍然会计算参数。如果后置条件可能很复杂,比如

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

    您可能会考虑使用 icelava 的建议来反映调用程序集以查找它是在调试还是发布中构建的 - 但是您必须使用某种委托来延迟计算 - 以确保它只在需要时完成。例如:

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

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

    【讨论】:

    • 是的,但我什至认为这对于这个特定的应用程序来说是不可接受的开销。
    【解决方案3】:

    自从我要洗澡离开家后,我还没有尝试过。

    1. 调用 Assembly.GetCallingAssembly() 以获取调用当前执行方法的方法(类)来自的程序集。
    2. Run a check on that Assembly object to see if it is Release or Debug build

    【讨论】:

      【解决方案4】:

      听起来你正在做的大部分事情已经使用Debug.Assert() 覆盖了。

      就此而言,这段代码只能在调试模式下运行(但你必须忍受 catch-block 的缓慢):

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

      【讨论】:

      • Debug.Assert() 仅适用于后置条件。如果我想使用相同的 API 来验证前置条件和后置条件,或者在仅调试和始终检查后置条件之间轻松切换,则不合适。
      【解决方案5】:

      看来我想要的东西不可用。我可能会满足于提供从Validationbool 的隐式转换,以便验证检查可以包含在Debug.Assert() 中。

      【讨论】:

        【解决方案6】:

        即使在程序编译后,也可以使用 bool 设置/更改 Debug Assert 方法,例如,如果该值来自项目用户设置:

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

        【讨论】:

          【解决方案7】:

          我不确定,但我认为您可以为此使用 ConditionalAttribute:是否发出调用取决于用户构建的类型,而不是您的库。您可以使用 Reflector 或 ILDasm 进行检查:编译您的示例并在 Reflector (ILDasm) 中查看示例项目中是否发出了调用。

          【讨论】:

            【解决方案8】:

            我有这种情况: 项目 A 调用 B 的 1 函数。 B 包括这个功能: Assembly.GetCallingAssembly().FullName 如果在调试模式下构建 B 然后运行,则此函数返回项目 A 的名称,如果在模式发布时构建,则返回项目 B 的名称。 我不知道发生这种情况的原因。 请支持我 谢谢

            【讨论】:

              猜你喜欢
              • 2020-02-18
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多