派生 class 的 c++/cli 静态构造函数未被调用
c++/cli static constructor of derived class is not called
如所述in another SO post of me 从 VS 2008 (.net 3.5) 迁移到 VS 2013(并使用 .net 4.0,而非 4.5)后,我发现我的应用程序有一个奇怪的行为。我发现不再调用 class 的静态构造函数(cctor)。因此,我将该应用程序分解为一个小的测试程序:
DLL testAssembly_2-0 和 testAssembly_4-0
(相似的内容;testAssembly_4-0 的名字带有 40
而不是 20
)
namespace testAssembly_20
{
public ref class Class20
{
public:
Class20 ()
{ Console::WriteLine (__FUNCTION__"()"); }
static Class20 ()
{ Console::WriteLine (__FUNCTION__"()" + " ms_iValue=" + ms_iValue);
ms_iValue = 2;
Console::WriteLine (__FUNCTION__"()" + " ms_iValue=" + ms_iValue); }
void func20 ()
{ Console::WriteLine (__FUNCTION__"()" + " ms_iValue=" + ms_iValue); }
protected:
static int ms_iValue = 1;
};
}
主VS2008
在VS 2008中编译testAssembly_2-0
和main
时(制作.net 2.0的汇编和应用),两种执行方式都运行正常(在[=107=中启动调试模式,直接启动exe) ):
int main ()
{
testAssembly_20::Class20^ oC20 = gcnew testAssembly_20::Class20;
oC20->func20 ();
}
// output:
// testAssembly_20::Class20::Class20 (static class constructor)() ms_iValue=1
// testAssembly_20::Class20::Class20 (static class constructor)() ms_iValue=2
// testAssembly_20::Class20::Class20()
// testAssembly_20::Class20::func20() ms_iValue=2
主VS2013
在 VS 2013 中编译 testAssembly_4-0
和 main
时(创建 .net 4.0 程序集和应用程序),并包括现有的 .net 2.0 testAssembly_2-0
(使用 app.config,请参阅我的链接 post), 它仍然有效,但与 IDE 调试到 exe 启动相比,它的行为不同。
IDE 调试产生如上的结果(一次使用 Class20
,一次使用 Class40
)。
exe start 调用 cctor
不是在 class 实例化时,而是在第一次访问静态成员时。这一定是由于 .net 4.0 引入的所谓 延迟初始化 ,据我最近几个小时的研究所知。
int main ()
{
testAssembly_40::Class40^ oC40 = gcnew testAssembly_40::Class40;
oC40->func40 ();
testAssembly_20::Class20^ oC20 = gcnew testAssembly_20::Class20;
oC20->func20 ();
}
// output of exe start:
// testAssembly_40::Class40::Class40 (static class constructor)() ms_iValue=1
// testAssembly_40::Class40::Class40 (static class constructor)() ms_iValue=2
// testAssembly_40::Class40::Class40()
// testAssembly_40::Class40::func40() ms_iValue=2
// testAssembly_20::Class20::Class20()
// testAssembly_20::Class20::Class20 (static class constructor)() ms_iValue=1
// testAssembly_20::Class20::Class20 (static class constructor)() ms_iValue=2
// testAssembly_20::Class20::func20() ms_iValue=2
DLL 增强
由于这还没有重现我的失败,我将 属性 添加到 class 以访问静态成员,就像我在原始应用程序中所做的那样。在 main()
中查询此 属性 只会导致不同的函数调用顺序(Class20 cctor
现在首先调用所有函数,直接在 main()
的开头)。但行为是正确的。
因此,我对我的原始应用程序更进了一步,并向两个程序集添加了派生的 classes:
public ref class Class20derived : Class20
{
public:
Class20derived ()
{ Console::WriteLine (__FUNCTION__"()"); }
static Class20derived ()
{ Console::WriteLine (__FUNCTION__"()" + " ms_iValue=" + ms_iValue);
ms_iValue = 3;
Console::WriteLine (__FUNCTION__"()" + " ms_iValue=" + ms_iValue); }
void func20derived ()
{ Console::WriteLine (__FUNCTION__"()" + " ms_iValue=" + ms_iValue); }
};
Class40derived is similar again.
主VS2008新
测试程序现在创建派生 class 的对象。两种执行方式都按预期运行(IDE,直接exe):
int main ()
{
testAssembly_20::Class20derived^ oC20D = gcnew testAssembly_20::Class20derived;
oC20D->func20 ();
}
// testAssembly_20::Class20::Class20 (static class constructor)() ms_iValue=1
// testAssembly_20::Class20::Class20 (static class constructor)() ms_iValue=2
// testAssembly_20::Class20derived::Class20derived (static class constructor)() ms_iValue=2
// testAssembly_20::Class20derived::Class20derived (static class constructor)() ms_iValue=3
// testAssembly_20::Class20::Class20()
// testAssembly_20::Class20derived::Class20derived()
// testAssembly_20::Class20::func20() ms_iValue=3
主VS2013新
测试程序现在创建两个派生 classes 的对象。它从 IDE 启动时按预期运行(与 VS2008 new 中的结果相同,一次使用 Class40,一次使用 Class20)。
但是启动exe时,结果报错:
int main ()
{
testAssembly_40::Class40derived^ oC40D = gcnew testAssembly_40::Class40derived;
oC40D->func40 ();
testAssembly_20::Class20derived^ oC20D = gcnew testAssembly_20::Class20derived;
oC20D->func20 ();
}
// testAssembly_40::Class40::Class40 (static class constructor)() ms_iValue=1
// testAssembly_40::Class40::Class40 (static class constructor)() ms_iValue=2
// testAssembly_40::Class40derived::Class40derived (static class constructor)() ms_iValue=2
// testAssembly_40::Class40derived::Class40derived (static class constructor)() ms_iValue=3
// testAssembly_40::Class40::Class40()
// testAssembly_40::Class40derived::Class40derived()
// testAssembly_40::Class40::func40() ms_iValue=3
// testAssembly_20::Class20::Class20()
// testAssembly_20::Class20derived::Class20derived()
// testAssembly_20::Class20::Class20 (static class constructor)() ms_iValue=1
// testAssembly_20::Class20::Class20 (static class constructor)() ms_iValue=2
--> where is the Class20derived cctor??
// testAssembly_20::Class20::func20() ms_iValue=2
为什么.net 2.0程序集派生的cctor()没有被调用?
这是 .net 4.0 惰性初始化的预期行为,还是我认为这是编译器中的错误?奇怪的是,.net 4.0 程序集使用正确,但 .net 2.0 程序集不正确。
此外,在底部 class 顶部:
为什么.net 4.0 cctor是在class实例化时调用的,而.net2.0 cctor是按需调用的?
编辑 1
我刚刚发现同一个应用程序(VS2008,增强的 DLL)在作为 exe 执行时有或没有 app.exe.config!
时表现不同
当出现 app.config 时,应用程序在 VS2013 中编译,这意味着它是错误的。
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup useLegacyV2RuntimeActivationPolicy="true">
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
</configuration>
但是我一删除 app.config,应用程序就运行良好。
所以我认为错误不在 VS C++/CLI 编译器内部,而是在 .net 4.0 CLR 本身内部...
我通过手动调用静态构造函数找到了解决方法。直到几分钟前我才知道这是可能的:
System::Runtime::CompilerServices::RuntimeHelpers::RunClassConstructor (
testAssembly_20::Class20derived::typeid->TypeHandle);
编辑:
最近我有一个问题,我的程序表现不同取决于是 运行 来自 VS2008 (这次不是 VS2013!) 或来自 exe,即使我手动调用了静态 cctor。
问题是错误的CLASS的cctor被执行了!很奇怪!
我的设计:
base A
derived B : A
derived C1 : B
derived C2 : B
我打电话给 C2.cctor
,但是 C1.cctor
是 运行。添加一些任意日志记录命令时,它的行为又有所不同并最终起作用。那是我决定完全删除 cctors 并引入 static Init()
的时候。
准备好遇到同样的情况!
您仍然可以手动调用 cctor
,它已经为我工作了很长时间。
我很想进一步调查和分析 MSIL,但当时我太忙了。
如所述in another SO post of me 从 VS 2008 (.net 3.5) 迁移到 VS 2013(并使用 .net 4.0,而非 4.5)后,我发现我的应用程序有一个奇怪的行为。我发现不再调用 class 的静态构造函数(cctor)。因此,我将该应用程序分解为一个小的测试程序:
DLL testAssembly_2-0 和 testAssembly_4-0
(相似的内容;testAssembly_4-0 的名字带有 40
而不是 20
)
namespace testAssembly_20
{
public ref class Class20
{
public:
Class20 ()
{ Console::WriteLine (__FUNCTION__"()"); }
static Class20 ()
{ Console::WriteLine (__FUNCTION__"()" + " ms_iValue=" + ms_iValue);
ms_iValue = 2;
Console::WriteLine (__FUNCTION__"()" + " ms_iValue=" + ms_iValue); }
void func20 ()
{ Console::WriteLine (__FUNCTION__"()" + " ms_iValue=" + ms_iValue); }
protected:
static int ms_iValue = 1;
};
}
主VS2008
在VS 2008中编译testAssembly_2-0
和main
时(制作.net 2.0的汇编和应用),两种执行方式都运行正常(在[=107=中启动调试模式,直接启动exe) ):
int main ()
{
testAssembly_20::Class20^ oC20 = gcnew testAssembly_20::Class20;
oC20->func20 ();
}
// output:
// testAssembly_20::Class20::Class20 (static class constructor)() ms_iValue=1
// testAssembly_20::Class20::Class20 (static class constructor)() ms_iValue=2
// testAssembly_20::Class20::Class20()
// testAssembly_20::Class20::func20() ms_iValue=2
主VS2013
在 VS 2013 中编译 testAssembly_4-0
和 main
时(创建 .net 4.0 程序集和应用程序),并包括现有的 .net 2.0 testAssembly_2-0
(使用 app.config,请参阅我的链接 post), 它仍然有效,但与 IDE 调试到 exe 启动相比,它的行为不同。
IDE 调试产生如上的结果(一次使用 Class20
,一次使用 Class40
)。
exe start 调用 cctor
不是在 class 实例化时,而是在第一次访问静态成员时。这一定是由于 .net 4.0 引入的所谓 延迟初始化 ,据我最近几个小时的研究所知。
int main ()
{
testAssembly_40::Class40^ oC40 = gcnew testAssembly_40::Class40;
oC40->func40 ();
testAssembly_20::Class20^ oC20 = gcnew testAssembly_20::Class20;
oC20->func20 ();
}
// output of exe start:
// testAssembly_40::Class40::Class40 (static class constructor)() ms_iValue=1
// testAssembly_40::Class40::Class40 (static class constructor)() ms_iValue=2
// testAssembly_40::Class40::Class40()
// testAssembly_40::Class40::func40() ms_iValue=2
// testAssembly_20::Class20::Class20()
// testAssembly_20::Class20::Class20 (static class constructor)() ms_iValue=1
// testAssembly_20::Class20::Class20 (static class constructor)() ms_iValue=2
// testAssembly_20::Class20::func20() ms_iValue=2
DLL 增强
由于这还没有重现我的失败,我将 属性 添加到 class 以访问静态成员,就像我在原始应用程序中所做的那样。在 main()
中查询此 属性 只会导致不同的函数调用顺序(Class20 cctor
现在首先调用所有函数,直接在 main()
的开头)。但行为是正确的。
因此,我对我的原始应用程序更进了一步,并向两个程序集添加了派生的 classes:
public ref class Class20derived : Class20
{
public:
Class20derived ()
{ Console::WriteLine (__FUNCTION__"()"); }
static Class20derived ()
{ Console::WriteLine (__FUNCTION__"()" + " ms_iValue=" + ms_iValue);
ms_iValue = 3;
Console::WriteLine (__FUNCTION__"()" + " ms_iValue=" + ms_iValue); }
void func20derived ()
{ Console::WriteLine (__FUNCTION__"()" + " ms_iValue=" + ms_iValue); }
};
Class40derived is similar again.
主VS2008新
测试程序现在创建派生 class 的对象。两种执行方式都按预期运行(IDE,直接exe):
int main ()
{
testAssembly_20::Class20derived^ oC20D = gcnew testAssembly_20::Class20derived;
oC20D->func20 ();
}
// testAssembly_20::Class20::Class20 (static class constructor)() ms_iValue=1
// testAssembly_20::Class20::Class20 (static class constructor)() ms_iValue=2
// testAssembly_20::Class20derived::Class20derived (static class constructor)() ms_iValue=2
// testAssembly_20::Class20derived::Class20derived (static class constructor)() ms_iValue=3
// testAssembly_20::Class20::Class20()
// testAssembly_20::Class20derived::Class20derived()
// testAssembly_20::Class20::func20() ms_iValue=3
主VS2013新
测试程序现在创建两个派生 classes 的对象。它从 IDE 启动时按预期运行(与 VS2008 new 中的结果相同,一次使用 Class40,一次使用 Class20)。
但是启动exe时,结果报错:
int main ()
{
testAssembly_40::Class40derived^ oC40D = gcnew testAssembly_40::Class40derived;
oC40D->func40 ();
testAssembly_20::Class20derived^ oC20D = gcnew testAssembly_20::Class20derived;
oC20D->func20 ();
}
// testAssembly_40::Class40::Class40 (static class constructor)() ms_iValue=1
// testAssembly_40::Class40::Class40 (static class constructor)() ms_iValue=2
// testAssembly_40::Class40derived::Class40derived (static class constructor)() ms_iValue=2
// testAssembly_40::Class40derived::Class40derived (static class constructor)() ms_iValue=3
// testAssembly_40::Class40::Class40()
// testAssembly_40::Class40derived::Class40derived()
// testAssembly_40::Class40::func40() ms_iValue=3
// testAssembly_20::Class20::Class20()
// testAssembly_20::Class20derived::Class20derived()
// testAssembly_20::Class20::Class20 (static class constructor)() ms_iValue=1
// testAssembly_20::Class20::Class20 (static class constructor)() ms_iValue=2
--> where is the Class20derived cctor??
// testAssembly_20::Class20::func20() ms_iValue=2
为什么.net 2.0程序集派生的cctor()没有被调用?
这是 .net 4.0 惰性初始化的预期行为,还是我认为这是编译器中的错误?奇怪的是,.net 4.0 程序集使用正确,但 .net 2.0 程序集不正确。
此外,在底部 class 顶部:
为什么.net 4.0 cctor是在class实例化时调用的,而.net2.0 cctor是按需调用的?
编辑 1
我刚刚发现同一个应用程序(VS2008,增强的 DLL)在作为 exe 执行时有或没有 app.exe.config!
时表现不同
当出现 app.config 时,应用程序在 VS2013 中编译,这意味着它是错误的。
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup useLegacyV2RuntimeActivationPolicy="true">
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
</configuration>
但是我一删除 app.config,应用程序就运行良好。
所以我认为错误不在 VS C++/CLI 编译器内部,而是在 .net 4.0 CLR 本身内部...
我通过手动调用静态构造函数找到了解决方法。直到几分钟前我才知道这是可能的:
System::Runtime::CompilerServices::RuntimeHelpers::RunClassConstructor (
testAssembly_20::Class20derived::typeid->TypeHandle);
编辑:
最近我有一个问题,我的程序表现不同取决于是 运行 来自 VS2008 (这次不是 VS2013!) 或来自 exe,即使我手动调用了静态 cctor。
问题是错误的CLASS的cctor被执行了!很奇怪!
我的设计:
base A
derived B : A
derived C1 : B
derived C2 : B
我打电话给 C2.cctor
,但是 C1.cctor
是 运行。添加一些任意日志记录命令时,它的行为又有所不同并最终起作用。那是我决定完全删除 cctors 并引入 static Init()
的时候。
准备好遇到同样的情况!
您仍然可以手动调用 cctor
,它已经为我工作了很长时间。
我很想进一步调查和分析 MSIL,但当时我太忙了。