【问题标题】:Order of constructors for a C# class: parameterized, default, and static?C# 类的构造函数顺序:参数化、默认和静态?
【发布时间】:2009-08-12 23:33:39
【问题描述】:

假设我有一个包含 3 个构造函数、一个默认(无参数)构造函数、一个参数化构造函数和一个静态构造函数的类。像这样:

public MyClass()  { ... }
public MyClass(string arg) : this()  { ...  }
static MyClass()  { ... }

假设我调用参数化构造函数,这些构造函数以什么顺序执行?

我认为它是静态的,然后是参数化的,然后是默认的。但是……我的经验并不同意这一点。


背景:我有一个将引用的 DLL 作为资源嵌入的应用程序。在运行时,应用程序通过

注册一个程序集解析器
static MyClass()
{
    AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(Resolver);
}

Resolver 方法的定义如下:

static System.Reflection.Assembly Resolver(object sender, ResolveEventArgs args)
{
    ....
} 

我知道 Resolver 可以通过它选择的任何方式生成程序集。在我的应用程序中,它执行了

Assembly.GetExecutingAssembly().GetManifestResourceStream(name);

其中 name 是嵌入资源的名称。然后读取该资源的所有字节,并对读取的字节块执行 Assembly.Load(byte[])。

一开始你可能觉得这很奇怪,但它确实有效。

你可能会说,你到底为什么要嵌入一个程序集,而不仅仅是 ILMerge? 好问题。我认为我需要嵌入,因为嵌入式程序集已签名,并且我没有重新签署合并程序集的密钥。所以我嵌入。

问题是这样的:假设我在类上声明了一个私有实例成员变量,该变量属于嵌入式程序集中定义的类型。就我而言,它是一个枚举,我还初始化了该枚举的值。

现在,如果静态构造函数已经运行,那么该私有成员上的初始化程序将没有问题运行。但我看到的是“找不到文件”错误 - 您的基本 Fusion 错误。

Unhandled Exception: System.IO.FileNotFoundException: Could not load file or assembly 'MyApp, Version=1.1.4.1, Culture=neutral, PublicKeyToken=edbe51ad942a3f5c' or one of its dependencies. The system cannot find the file specified.
File name: 'MyApp, Version=1.1.4.1, Culture=neutral, PublicKeyToken=edbe51ad942a3f5c'

WRN: Assembly binding logging is turned OFF.
To enable assembly bind failure logging, set the registry value[HKLM\Software\Microsoft\Fusion!EnableLog] (DWORD) to 1.
Note: There is some performance penalty associated with assembly bind failure logging.
To turn this feature off, remove the registry value [HKLM\Software\Microsoft\Fusion!EnableLog].

如果我删除私​​有实例变量,则不会收到 Fusion 错误。

我可以使用该类型的变量,或者嵌入程序集中定义的任何其他类型,稍后,只要它们没有被初始化为类中的成员实例变量。我可以在实例方法中使用类型,没问题。


写这篇文章,我想我可能已经想出了我自己问题的答案。也许这是一个 JIT 时间问题:也许实例构造函数在静态构造函数运行之前是 JIT 的。这会,也许?导致 Fusion 错误?

任何人有任何见解?

这不是一个非常关键的问题,因为我可以重新设计类来避免这个问题,删除所有依赖于嵌入式程序集的实例变量。但我想了解它。

【问题讨论】:

  • 上面的“类”不是很清楚你的意思,是在嵌入式程序集中还是在加载类中?这可能很重要,因为您可能会遇到静态 ctor 的排序和循环问题。
  • “类”在我正在编写的代码中,它将使用外部程序集中的类型。我不知道上面的问题在哪里不清楚。如果我知道我可以编辑 Q 来澄清一下。

标签: .net constructor class-design fusion


【解决方案1】:

就顺序而言,您是对的。

静态构造函数先运行,然后是非参数化构造函数,然后是参数化构造函数。

JIT 时间应该不是问题。 CLR 保证您的静态构造函数将在构造任何实例之前完成。

但是,程序集解析是在您的静态构造函数触发之前发生的。运行时需要在调用任何静态构造之前解析程序集(及其依赖项)。这就是你遇到这个问题的原因。

【讨论】:

  • 是的,我可以看到程序集在静态构造函数触发之前被引用。我认为你完全正确。问题是,为什么会出现这种情况,只有当实例变量使用嵌入式程序集中定义的类型时?
  • 程序集需要解析才能构造类型。当您访问程序集中的类型时,它需要加载该程序集和潜在的依赖程序集(调用程序集解析),然后它运行静态初始化程序,然后运行该类型的静态构造函数,然后运行您的实例构造函数。跨度>
  • 是的,Reed - 这就是问题所在。这解释了我观察到的情况。
猜你喜欢
  • 2011-02-20
  • 1970-01-01
  • 1970-01-01
  • 2021-08-31
  • 2014-07-09
  • 1970-01-01
  • 2010-09-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多