6

好的,所以我遇到了以下问题,引起了人们的注意。

由于各种原因,我有一个测试设置,其中 TestingAssembly.dll 中的测试类依赖于 BaseTestingAssembly.dll 中的 TestingBase 类。与此同时,TestBase 所做的一件事是在它自己和调用程序集中寻找某个嵌入式资源

所以我的 BaseTestingAssembly 包含以下几行......

public class TestBase {    
  private static Assembly _assembly;
  private static Assembly _calling_assembly;

  static TestBase() {
    _assembly = Assembly.GetExecutingAssembly();
    _calling_assembly = Assembly.GetCallingAssembly();
  }
}

静态,因为我认为这些程序集在应用程序的整个生命周期中都是相同的,所以为什么要在每次测试中重新计算它们。

但是,在运行此程序时,我注意到 _assembly 和 _calling_assembly 都分别设置为 BaseTestingAssembly 而不是 BaseTestingAssembly 和 TestingAssembly。

将变量设置为非静态并在常规构造函数中对其进行初始化修复了此问题,但我很困惑为什么会发生这种情况。我认为静态构造函数在第一次引用静态成员时运行。这只能来自我的 TestingAssembly,它应该是调用者。有谁知道可能发生了什么?

4

3 回答 3

6

静态构造函数由运行时调用,而不是由用户代码直接调用。您可以通过在构造函数中设置断点然后在调试器中运行来查看这一点。调用链中紧接其上方的函数是本机代码。

编辑:静态初始化程序在与其他用户代码不同的环境中运行的方式有很多。其他一些方法是

  1. 它们被隐式保护免受多线程导致的竞争条件
  2. 您无法从初始化程序之外捕获异常

一般来说,最好不要将它们用于任何过于复杂的事情。您可以使用以下模式实现单初始化:

private static Assembly _assembly;
private static Assembly Assembly {
  get {
    if (_assembly == null) _assembly = Assembly.GetExecutingAssembly();
    return _assembly;
  }
}

private static Assembly _calling_assembly;
private static Assembly CallingAssembly {
  get {
    if (_calling_assembly == null) _calling_assembly = Assembly.GetCallingAssembly();
    return _calling_assembly;
  }
}

如果您期望多线程访问,请添加锁定。

于 2008-09-23T16:17:23.253 回答
1

我认为答案在C# static constructors的讨论中。我最好的猜测是静态构造函数是从意外的上下文中调用的,因为:

用户无法控制程序中何时执行静态构造函数

于 2008-09-23T16:14:45.430 回答
1

Assembly.GetCallingAssembly() 仅返回调用堆栈中第二个条目的程序集。这可能很大程度上取决于调用方法/getter/构造函数的位置。这是我在库中为获取不在我的库中的第一个方法的程序集所做的。(这甚至适用于静态构造函数。)

private static Assembly GetMyCallingAssembly()
{
  Assembly me = Assembly.GetExecutingAssembly();

  StackTrace st = new StackTrace(false);
  foreach (StackFrame frame in st.GetFrames())
  {
    MethodBase m = frame.GetMethod();
    if (m != null && m.DeclaringType != null && m.DeclaringType.Assembly != me)
      return m.DeclaringType.Assembly;
  }

  return null;
}
于 2008-12-04T16:07:38.727 回答