C#6/C++ 的 ref 关键字错误

16

我尝试使用VS2015运行我的现有解决方案并出现了一些新的有效错误(例如编译器之前未检测到的“不可访问代码”),但是我也在这一行代码上遇到了一个错误:

bool bWasAlreadyLocked = false;
oEnv.LockDoc(oWarnings, oEventDoc, ref bWasAlreadyLocked);

我收到了以下错误:

  

Error CS1503 第三个参数:无法从“ref bool [mscorlib,Version = 4.0.0.0,Culture = neutral,PublicKeyToken = b77a5c561934e089]”转换为“ref bool [mscorlib,Version = 4.0.0.0,Culture = neutral,PublicKeyToken = b77a5c561934e089]”

我看不出为什么会抛出这个错误,因为类型显然是匹配的。这是新编译器中的一个错误吗,还是ref关键字的行为已经改变了?

在这种情况下,函数是一个 C++ 函数,使用从 c++ 类派生的 C# 类导入到 C# 中。其签名如下:

void CBkgDocEnvX::LockDoc(
CFIWarningList ^oWarnings,
CBaseDoc ^oBaseDoc,
// Output
bool %rbWasAlreadyLocked)

可能值得一提的是,我目前选择在解决方案中使用VS2013 c++编译器来编译c++源代码,因此c++方面应该与之前相同。我猜测是c#和c++之间的互操作发生了变化。


1
LockDoc 的签名是什么? - Patrick Hofman
查了一下,这是一个C++函数。 - Manuel Schweigert
7
嗯,那是一个漏洞。您需要考虑到错误信息也可能有漏洞。C++的布尔类型与托管布尔类型不同,如果将其声明为System::Boolean,可能会更好。但不清楚您是否使用的是C++/CX还是C++/CLI。请使用connect.microsoft.com报告beta版中的漏洞。 - Hans Passant
我的猜测是(如果这不是一个错误),bool %rbWasAlreadyLocked 被编译成了一个修改过的类型(在 CIL 中为 modreq),而这些类型通常与 C# 不兼容。你能否将程序集上传到某个地方? - IS4
你在 C# 项目中使用的是哪个版本的 .NET? - twitchax
显示剩余8条评论
4个回答

1
当两个项目类型不兼容时,我会遇到这种编译错误。通常情况下,即使被引用的程序集不受引用项目的.NET配置文件类型支持,Visual Studio也会允许我向可移植类库项目(或.NET 4.0项目)添加引用。
对我来说最常见的情况是使用.NET 4.0项目并尝试引用一个在其配置文件设置中指定为.NET 4.5而不是旧版.NET 4的可移植类库项目。当我从我的.NET 4.0项目中引用PCL程序集时,我继续获得完整的智能感知支持(例如,在编辑源代码时,智能感知将显示所有命名空间、类和属性),但在编译时我会遇到与你所遇到的相同类型的错误;更具体地说,当我编译解决方案时,编译指示存在库不匹配,但列出了完全相同的库、版本和公钥,它说正在查找。
检查项目属性,验证它们是否兼容。

1

为了确保,您应该检查此处指出的要点。

  1. 只有 L-Value 可以通过引用传递。L-Value 是变量和其他表达式,可以出现在赋值的左侧。这些包括局部变量、字段访问、指针解引用和数组元素访问。L-Value 不包括属性访问,因为它们没有可识别的机器地址,也不包括只读字段,这些字段受 CLR 限制。
  2. Ref 参数不能成为扩展方法的目标。对于值类型,扩展方法调用很昂贵,因为“this”参数是按值复制的。这也意味着值类型不能有可变的扩展方法。这与实例方法形成了鲜明对比,后者通过引用传递值类型的“this”参数。
  3. Ref 参数不能在操作符重载函数中使用。

您可以在 这里 找到更多信息。


这听起来很合理,但并不新鲜。既然代码可以在VS2013中运行,我怀疑它是由其中一个原因引起的,但如果我错了,请纠正我。此外,您可以查看上面的ref参数声明。 - Manuel Schweigert

1
事实证明,可以通过在参数中显式添加一个out属性来修复此错误。
显式添加[Out]到ref参数似乎有助于新的C#编译器识别这些是相同的类型并接受它们。我们的交互解决方案中的方法现在看起来像这样:
using namespace System::Runtime::InteropServices;

...

virtual void LockDoc(
   CFIWarningList ^oWarnings,
   CBaseDoc ^oBaseDoc,
// Output
   [Out] bool %rbWasAlreadyLocked
   ) override;

0
你可以尝试使用对象数据类型而不是布尔类型。之后,你可以将其解析为布尔类型。

1
或者我可以不使用VS2015,而不是在整个项目中的数百个位置删除输入。;) - Manuel Schweigert

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接