C#/VB.NET ASP.NET应用中静态构造函数从未被调用问题
问题原因
- 最核心的原因是调用的类型和你定义静态构造函数的类型不匹配。你VB代码中调用路径写的是
Commerce.Database.Model.Commerce.CheckSchema(),VB的类型解析默认会优先拼接当前项目的根命名空间:如果你的VB项目根命名空间刚好是Commerce,这个路径实际会解析为当前VB项目内的Database.Model.Commerce类,而不是你在C#类库里写的、继承自DbContext的那个Commerce类。两个同名类分属不同的命名空间/程序集,是完全独立的类型,你写的静态构造函数属于C#类库中的类,你根本没有访问到这个类的任何成员,它的静态构造函数自然永远不会触发,你观察到的CheckedIn始终为true,是解析到的错误类型的字段值,和你写的逻辑无关。 - 其次存在引用版本问题的可能:如果VB项目引用的C#类库是旧编译版本,你后续新增的静态构造函数逻辑根本没有被编译到被引用的dll中,运行时加载的旧版本类没有你写的静态构造函数,自然不会执行。
- 你当前的静态初始化逻辑本身存在设计缺陷:你在静态构造函数里先把
CheckedIn设为false,紧接着就调用CheckSchema(),而CheckSchema()检测到CheckedIn为false后会立刻把它设为true,等于静态构造函数执行完成后CheckedIn本来就会是true,你预期的“未完成检查”状态根本不会对外暴露,加上静态构造函数执行阶段类型初始化尚未完成,此时调用类自身的静态方法很容易触发重入、字段初始化顺序错乱的问题。
修复方案
- 第一步先确认类型匹配:在VB的调用代码中,选中
CheckSchema方法前的Commerce类名,按F12执行「转到定义」,如果跳转后的代码里看不到你写的静态构造函数,说明类型解析错误。调用时使用全局全限定名,在命名空间前加Global关键字强制从根命名空间解析,避免被项目默认根命名空间干扰,例如Global.你的C#类库实际命名空间.Commerce.CheckSchema()。 - 第二步修正类库引用:删除VB项目中对C#类库dll的文件引用,改为直接添加项目引用,确保每次编译都能拿到最新的类库代码,避免旧版本dll缓存导致的逻辑不生效。
- 第三步重构静态初始化逻辑,移除静态构造函数中对
CheckSchema()的调用,避免初始化阶段重入,同时加锁保证多线程环境下schema检查只执行一次,参考代码如下:
public partial class Commerce : DbContext { // 静态字段直接初始化默认值,不要在其他partial类分片里重复定义这些字段 private static bool CheckedIn = false; private static bool IsUpToDate = false; // 静态构造函数只保留必须在类型初始化阶段执行的逻辑,不要调用CheckSchema static Commerce() { // 移除这里的CheckSchema()调用 } public static bool CheckSchema(Action<string,Exception> logMethod = null, bool force = false) { if (force) { // 强制重检的逻辑可以在这里重置CheckedIn标记 lock (typeof(Commerce)) { CheckedIn = false; } } if (CheckedIn) return IsUpToDate; // 加双重检查锁保证多线程下只执行一次检查 lock (typeof(Commerce)) { if (CheckedIn) return IsUpToDate; // 这里写实际的schema检查逻辑 IsUpToDate = true; // 替换为你实际的检查结果 CheckedIn = true; } return IsUpToDate; } }
- 最后检查所有
Commerce的partial类分片,确认没有重复定义CheckedIn、IsUpToDate静态字段,也没有其他地方给这两个字段写冲突的初始值。
内容的提问来源于stack exchange,提问作者Sarfaraz Jamal
相关产品推荐
相关产品推荐

