У меня есть ситуация, когда мне нужно сгенерировать класс с большой строкой 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);
}