设置
在尝试在本地C ++库的C ++ / CLI包装器中的翻译单元范围创建静态对象时,我遇到了使用auto关键字的问题。 C ++ / CLI包装器纯粹是功能性的,因此我需要使用ConcurrentDictionary在调用之间保持一些状态(以处理Managed< - > Native委托转换)。我首先尝试了这个(简化):
static ConcurrentDictionary<String^, String^>^ GlobalData1 = gcnew ConcurrentDictionary<String^, String^>();
但这无法编译:
具有静态存储持续时间的变量不能具有句柄或跟踪引用类型
为简单起见,我决定继续使用类型演绎,同时我发现了问题:
static auto GlobalData3 = gcnew ConcurrentDictionary<String^, String^>();
令我惊讶的是这个编译和链接!我继续编写了一段时间的代码,然后运行了使用C ++ / CLI包装器的C#测试应用程序并收到了未处理的运行时异常:
未处理的异常:System.IO.FileLoadException:无法加载文件或程序集'DotNetTestLibWrapper,Version = 1.0.6111.33189,Culture = neutral,PublicKeyToken = null'或其依赖项之一。无法找到或加载类型。 (HRESULT的例外情况:0x80131522)---&gt; System.TypeLoadException:从程序集中键入'''DotNetTestLibWrapper,Version = 1.0.6111.33189,Culture = neutral,PublicKeyToken = null'有一个非法类型的字段。
自从我做了其他编辑后,我没有立即知道问题是什么。我终于通过打开Fusion日志和使用Fuslogvw.exe获得了更多信息。问题在于推断类型为静态ConcurrentDictionary。
我创建了SSCCE来证明问题:https://github.com/calebwherry/DotNetWrapperForNativeCppLibrary
MSVS版本:
Microsoft Visual Studio社区2015版本14.0.25431.01更新3 Microsoft .NET Framework版本4.6.01038
问题
这两者都会导致编译错误:
static ConcurrentDictionary<String^, String^>^ GlobalData1 = gcnew ConcurrentDictionary<String^, String^>();
static auto^ GlobalData2 = gcnew ConcurrentDictionary<String^, String^>();
但是这会编译+链接,但会导致关于非法类型的未处理的运行时异常:
static auto GlobalData3 = gcnew ConcurrentDictionary<String^, String^>();
发生了什么事,为什么会这样? MSVS似乎认为(读:IntelliSense这样说)auto
和auto^
定义是相同的。但是,他们显然不是因为一个编译而另一个没编译。
注意:在阅读了一些关于原始编译器问题之后,问题的实际解决方案是:
ref struct GlobalData
{
static ConcurrentDictionary<String^, String^>^ GlobalData4 = gcnew ConcurrentDictionary<String^, String^>();
};
哪个好,我只是好奇实际的类型演绎是什么。
答案 0 :(得分:5)
Hmya,编译器错误,它不应该允许你这样声明它。毫无疑问,由C ++ 11引起的变化,需要禁止此声明的额外检查在声明中不能与auto
一起使用。
您尝试调用的臭名昭着的SIOF(静态初始化命令Fiasco)不是.NET功能。但这正是你在这里得到的,编译器生成的初始化器(通常仅用于非托管代码)导致构造函数运行得太早。从调试器跟踪中很难看出完全出错的地方,除了它不是很好。但当然最基本的问题是模块初始化器需要首先运行以设置C ++ / CLI的执行环境。在此之前任何本机C ++初始化程序。那还没有发生。
您需要以正确的方式执行此操作,静态成员由类型初始化程序(也称为静态构造函数,即.cctor)初始化。在使用任何类成员之前,CLR会自动调用它。您不必显式编写该构造函数,编译器会自动从字段初始化表达式中为您编写它。
ref class Globals {
public:
static ConcurrentDictionary<String^, String^>^ Data1 = gcnew ConcurrentDictionary<String^, String^>();
// etc...
};