我有一种情况,我需要生成一个带有大字符串 const 的类。我无法控制的代码导致我生成的 CodeDom 树被发送到 C# 源代码,然后编译为更大程序集的一部分。
不幸的是,我遇到了这样一种情况,如果此字符串的长度在 Win2K8 x64 中超过 335440 个字符(在 Win2K3 x86 中为 926240),C# 编译器将退出并出现致命错误:
MSDN 说 CS1647 是“编译器中的堆栈溢出”(不是双关语!)。仔细观察,我确定 CodeDom “很好地”将我的字符串 const 包装在 80 个字符处。这导致编译器连接超过 4193 个字符串块,这显然是 x64 NetFx 中 C# 编译器的堆栈深度。CSC.exe 必须在内部递归地评估此表达式以“补充”我的单个字符串。
我最初的问题是:“有人知道改变代码生成器如何发出字符串的变通方法吗? ”我无法控制外部系统使用 C# 源作为中间体的事实,我希望这是一个常量(而不是而不是字符串的运行时连接)。
或者,我如何制定这个表达式,以便在一定数量的字符之后,我仍然能够创建一个常量,但它是由多个大块组成的?
完整的复制在这里:
// this string breaks CSC: 335440 is Win2K8 x64 max, 926240 is Win2K3 x86 max
string HugeString = new String('X', 926300);
CodeDomProvider provider = CodeDomProvider.CreateProvider("C#");
CodeCompileUnit code = new CodeCompileUnit();
// namespace Foo {}
CodeNamespace ns = new CodeNamespace("Foo");
code.Namespaces.Add(ns);
// public class Bar {}
CodeTypeDeclaration type = new CodeTypeDeclaration();
type.IsClass = true;
type.Name = "Bar";
type.Attributes = MemberAttributes.Public;
ns.Types.Add(type);
// public const string HugeString = "XXXX...";
CodeMemberField field = new CodeMemberField();
field.Name = "HugeString";
field.Type = new CodeTypeReference(typeof(String));
field.Attributes = MemberAttributes.Public|MemberAttributes.Const;
field.InitExpression = new CodePrimitiveExpression(HugeString);
type.Members.Add(field);
// generate class file
using (TextWriter writer = File.CreateText("FooBar.cs"))
{
provider.GenerateCodeFromCompileUnit(code, writer, new CodeGeneratorOptions());
}
// compile class file
CompilerResults results = provider.CompileAssemblyFromFile(new CompilerParameters(), "FooBar.cs");
// output reults
foreach (string msg in results.Output)
{
Console.WriteLine(msg);
}
// output errors
foreach (CompilerError error in results.Errors)
{
Console.WriteLine(error);
}