大きな文字列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);
}