Обходной путь для C # CodeDom, вызывающий переполнение стека (CS1647) в csc.exe?
У меня есть ситуация, когда мне нужно сгенерировать класс с большой строкой const. Код вне моего контроля приводит к тому, что мое сгенерированное дерево CodeDom отправляется в исходный код C #, а затем компилируется как часть большей сборки.
К сожалению, я столкнулся с ситуацией, когда, если длина этой строки превышает 335440 символов в Win2K8 x64 (926240 в Win2K3 x86), компилятор C # завершается с фатальной ошибкой:
фатальная ошибка CS1647: выражение слишком длинное или сложное для компиляции рядом с 'int'
MSDN говорит, что CS1647 - это «переполнение стека в компиляторе» (не каламбур!). Присмотревшись повнимательнее, я определил, что CodeDom «красиво» оборачивает мою строку const в 80 символов. Это заставляет компилятор объединять более 4193 фрагментов строки, что, по-видимому, является глубиной стека компилятора C # в x64 NetFx. 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);
}