C#赢得';t编译开头附近有的长常量字符串

本文关键字:字符串 常量 开头 赢得 编译 | 更新日期: 2023-09-27 18:29:45

我遇到了一个特殊的情况,在创建某些类型的字符串时会出现以下错误:

写入调试信息时出现意外错误--"调用COM组件时返回错误HRESULT E_FAIL。"

这个错误对于Stack Overflow来说并不新鲜(请参阅这个问题和这个问题),但出现的问题与这个问题无关。

对我来说,当我创建一个特定长度的常量字符串时,就会发生这种情况,该字符串在开头附近的某个地方包含一个空终止字符('0)。

要复制,首先生成一个适当长度的字符串,例如使用:

var s = new string('a', 3000);

在运行时获取结果字符串(例如,立即窗口或将鼠标悬停在变量上并复制其值)。然后,用它做一个const

const string history = "aaaaaa...aaaaa";

最后,在某个地方放一个'0

const string history = "aaaaaaaaaaaa'0aa...aaaaa";

我注意到的一些事情:

  • 如果将'0放在末尾附近,则不会发生错误
  • 使用.NET Framework 4.6.1和4.5进行复制
  • 如果字符串短,则不会发生
  • 编辑:下面的评论中提供了更珍贵的信息

知道为什么会发生这种事吗?是某种虫子吗?

编辑:Bug文件,包括来自评论的信息。谢谢大家。

C#赢得';t编译开头附近有�的长常量字符串

我会稍微讨论一下这个问题。此问题同时出现在VS2015和早期版本中。因此,与C#编译器本身无关,这在ISymUnmanagedWriter2::DefineConstant2()实现方法中出错。ISymUnmanagedWriter2是一个COM接口,是所有编译器使用的.NET基础结构的一部分。并且被Roslyn和遗留的C#编译器使用。

Roslyn源代码中使用该方法的注释(实际上可以追溯到CCI项目)足够有启发性,该方法之前就发现了问题:

// EDMAURER If defining a string constant and it is too long (length limit is undocumented), this method throws
// an ArgumentException.
// (see EMITTER::EmitDebugLocalConst)
try
{
    this.symWriter.DefineConstant2(name, value, constantSignatureToken);
}
catch (ArgumentException)
{
    // writing the constant value into the PDB failed because the string value was most probably too long.
    // We will report a warning for this issue and continue writing the PDB.
    // The effect on the debug experience is that the symbol for the constant will not be shown in the local
    // window of the debugger. Nor will the user be able to bind to it in expressions in the EE.
    //The triage team has deemed this new warning undesirable. The effects are not significant. The warning
    //is showing up in the DevDiv build more often than expected. We never warned on it before and nobody cared.
    //The proposed warning is not actionable with no source location.
}
catch (Exception ex)
{
    throw new PdbWritingException(ex);
}

吞噬例外,tsk,tsk。在你的案例中,最后一个捕获条款就失效了。他们确实深入挖掘了一点,对字符串长度问题进行了逆向工程:

internal const int PdbLengthLimit = 2046; // Empirical, based on when ISymUnmanagedWriter2 methods start throwing.

这相当接近''0开始投球的地方,我得到了2034。当然,你或这里的任何人对此都无能为力。你所能做的就是在connect.microsoft.com上报告这个错误。但希望你能看到墙上的文字,修复它的可能性很小。这是一个没有人再维护的代码,它现在有"未记录"的状态,从其他评论来看,这可以追溯到.NET之前很久。Ed Maurer也不是:)

解决方法应该足够简单,在运行时将这条字符串粘在一起。

我能够将问题重新编码。然后我把声明改为:

const string history=@"aaa''0aaa…很多aaa…aaa";

再试一次,它编译得很好。