.net 4.0 c++/未调用派生类的cli静态构造函数
如上所述,在从VS 2008(.net 3.5)迁移到VS 2013(并使用.net 4.0,而不是4.5)之后,我看到我的应用程序出现了一种奇怪的行为。我发现类的静态构造函数(cctor)不再被调用。因此,我将应用程序分解为一个小测试程序: DLL测试组装单元2-0和测试组装单元4-0.net 4.0 c++/未调用派生类的cli静态构造函数,.net-4.0,c++-cli,.net-2.0,derived-class,static-constructor,.net 4.0,C++ Cli,.net 2.0,Derived Class,Static Constructor,如上所述,在从VS 2008(.net 3.5)迁移到VS 2013(并使用.net 4.0,而不是4.5)之后,我看到我的应用程序出现了一种奇怪的行为。我发现类的静态构造函数(cctor)不再被调用。因此,我将应用程序分解为一个小测试程序: DLL测试组装单元2-0和测试组装单元4-0 (类似内容;testAssembly_4-0的名称为40,而不是20) 主VS2008 在VS 2008中编译testAssembly_2-0和main时(制作.net 2.0程序集并应用它),它在两种执行方式
(类似内容;testAssembly_4-0的名称为
40
,而不是20
)
主VS2008在VS 2008中编译
testAssembly_2-0
和main
时(制作.net 2.0程序集并应用它),它在两种执行方式下都按预期运行(在IDE中启动调试模式,直接启动exe):
主VS2013在VS 2013中编译
testAssembly_4-0
和main
时(创建.net 4.0程序集和应用程序),包括现有的.net 2.0 testAssembly_2-0
(使用app.config,请参阅我的链接帖子),它仍然可以工作,但与IDE调试和exe启动相比,它的行为有所不同。IDE调试产生上述结果(一次使用
Class20
,一次使用Class40
)。exe start不是在类实例化时调用
cctor
,而是在第一次访问静态成员时调用。这一定是由于.NET4.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由于这还没有重现我的失败,我在类中添加了一个属性来访问静态成员,正如我在原始应用程序中所做的那样。在
main()
中查询此属性只会导致不同的函数调用顺序(现在首先调用Class20 cctor
,直接在main()
的开头)。但这种行为是正确的
因此,我向我的原始应用程序又迈进了一步,向两个程序集添加了派生类:
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新版本测试程序现在创建派生类的对象。它以两种执行方式(IDE、exe直接)按预期运行: 主VS2013新增
测试程序现在创建两个派生类的对象。它从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()?这是.NET4.0延迟初始化的预期行为,还是编译器中的错误?奇怪的是,.NET4.0程序集使用正确,而.NET2.0程序集使用不正确 此外,在顶部的基类:
为什么在类实例化时调用.net 4.0 cctor,而在需要时调用.net 2.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。
问题是执行了错误类的cctor很奇怪
我的设计:
base A
derived B : A
derived C1 : B
derived C2 : B
我调用了C2.cctor
,但运行了C1.cctor
。当添加一些任意的日志命令时,它再次表现出不同的行为,并最终起作用。这时我决定完全删除cctor,并引入一个static Init()
准备好迎接同样的挑战您仍然可以手动调用
cctor
,它已经为我工作了很长时间
我很想进一步调查和分析MSIL,但当时我太忙了。WRT“这是编译器中的一个错误吗”,几年前我曾向Microsoft Connect发布了一份错误报告。当时,语言和CLR规范中存在相互冲突的要求。遗憾的是,我似乎再也无法访问该错误报告了。它(与)相关吗?不知道,我从该链接获得“页面未找到您请求的内容找不到,或者您没有查看该内容的权限。”。让我在注销后再试一次…看起来他们破坏了我的帐户,我可以在未登录时查看更多问题。这看起来很相关,但不是我想的那样。当您或多或少地确认这是一个bug时,我现在在VS2013中创建了一个bug报告:我在C#(.Net 4.0)中遇到了相同或非常类似的问题,显式调用类构造函数是以我想要的方式解决它的唯一方法。我的案例涉及抽象类和派生类以及静态构造函数和静态字段初始化。
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup useLegacyV2RuntimeActivationPolicy="true">
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
</configuration>
System::Runtime::CompilerServices::RuntimeHelpers::RunClassConstructor (
testAssembly_20::Class20derived::typeid->TypeHandle);
base A
derived B : A
derived C1 : B
derived C2 : B