问题描述
作为另一SO后我的描述 我看到VS 2008(移动后,我的应用程序的一个奇怪的行为。 .NET 3.5)到VS 2013(使用.NET 4.0,而不是4.5)。我发现一个类的静态构造函数(cctor)不叫了。所以我打破了应用程序分解成一个小的测试程序:
As described in another SO post of me I saw a strange behaviour of my application after moving from VS 2008 (.net 3.5) to VS 2013 (and using .net 4.0, not 4.5). I found that the static constructor (cctor) of a class was not called any more. Therefore I broke the application down into a small test program:
的DLL testAssembly_2-0和testAssembly_4-0
(类似的内容; testAssembly_4-0拥有,而不是用 40
名称 20
)
DLLs testAssembly_2-0 and testAssembly_4-0
(similar content; testAssembly_4-0 has names with 40
instead of 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
当编译 testAssembly_2-0
和主
在VS 2008中(使.NET 2.0组件和应用的话),它运行如预期中的两个执行方式(开始调试模式IDE,直接启动exe文件):
main VS2008
When compiling testAssembly_2-0
and main
in VS 2008 (making .net 2.0 assembly and application of it), it runs as expected in both execution ways (starting debugging mode in IDE, starting exe directly):
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
当编译 testAssembly_4-0
和主
在VS 2013(创建.NET 4.0组件和应用程序),并包括现有的 .NET 2.0 testAssembly_2-0
(使用的app.config,看到我的帖子链接),它仍然有效,,但它具有不同的行为相比IDE调试到exe启动。的
IDE调试其结果作为上述(一次使用 Class20
和曾经与 Class40
)。
exe文件开始调用 cctor
不在类实例化,但是当静态成员是第一次访问。这必须是由于所谓的延迟初始化的这是在过去的几个小时引入.NET 4.0,据我所知现在通过我的研究。
main VS2013
When compiling testAssembly_4-0
and main
in VS 2013 (creating .net 4.0 assembly and application), and including the existing .net 2.0 testAssembly_2-0
(using app.config, see my linked post), it still works, but it behaves differently compared IDE debugging to exe start.
IDE debugging produces the result as above (once with Class20
and once with Class40
).
exe start calls the cctor
not at class instantiation, but when the static member is first time accessed. This must be due to the so-called lazy initialization that was introduced with .net 4.0, as far as I know now by my research during the last couple of hours.
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()
)。但行为是正确的。
DLLs enhanced
As this did not yet reproduce my failure, I added a property to the class to access the static member, as I also do it in my original application. Querying this property in main()
just led to a different order of function calls (the Class20 cctor
was now called first of all functions, directly at the beginning of main()
). But the behaviour was correct.
所以我进了一步走向我原来的应用程序,并添加派生类到两个组件:
Therefore I went one step further towards my original application and added derived classes to both assemblies:
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直接):
main VS2008 new
The test program now creates an object of the derived class. It runs as expected in both execution ways (IDE, exe directly):
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新
测试程序现在既创造派生类的对象。当被从IDE(同样的结果Class40一次与Class20在VS2008新,一次)开始它运行正常。
但是在开始的exe时,其结果是错误的:
main VS2013 new
The test program now creates objects of both derived classes. It runs as expected when being started from the IDE (same result as in VS2008 new, once with Class40 and once with Class20).
But when starting the exe, the result is faulty:
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的程序集是没有的。
Why is the derived cctor() of the .net 2.0 assembly not called?
Is this an intended behaviour of the .net 4.0 lazy initialization or, which I assume, is it a bug in the compiler? The strange thing here is, that the .net 4.0 assembly is used correctly, but the .net 2.0 assembly isn't.
另外,在顶部的基类:
为什么.NET 4.0 cctor所谓的类的实例,但.net2.0 cctor被称为需求?
Also, at the base classes at the top:
Why is the .net 4.0 cctor called at class instantiation, but the .net2.0 cctor is called on demand?
我刚刚发现,同一个应用程序(VS2008,增强的DLL)的行为有所不同,当正在执行的EXE带或不带app.exe.config!
当在app.config为present,该应用程序的工作原理被编译在VS2013,这意味着,这是错误的。
I just found that one and the same application (VS2008, DLLs enhanced) behaves differently when being executed as exe with or without an app.exe.config!
When the app.config is present, the application works as being compiled in VS2013, which means, it is faulty.
<?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 CLR 4.0本身...
But as soon as I delete the app.config, the application works well.
So I think that the bug is not inside the VS C++/CLI compiler, but inside the .net 4.0 CLR itself...
推荐答案
我已经找到了解决办法通过手动调用静态构造函数。我不知道,直到我读它几分钟前,这是甚至有可能:
I have found a workaround by calling the static constructor manually. I didn't know that this is even possible until I read it a few minutes ago:
System::Runtime::CompilerServices::RuntimeHelpers::RunClassConstructor (
testAssembly_20::Class20derived::typeid->TypeHandle);
这篇关于派生类C ++ / CLI静态构造函数不叫的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!