Mam sytuację, w której muszę wygenerować klasę z dużą ciąg const. Kod spoza mojej kontroli powoduje, że moje wygenerowane drzewo CodeDom jest emitowane do źródła C#, a następnie kompilowane jako część większego złożenia.Obejście problemu dla C# CodeDom powodującego przepełnienie stosu (CS1647) w csc.exe?
Niestety, mam biegać w sytuacji, w której, jeśli długość tego ciągu przekracza 335440 znaków w Win2K8 x64 (926240 w Win2K3 x86), wyjść kompilator C# z fatalnym błędzie:
fatal error CS1647: An expression is too long or complex to compile near 'int'
MSDN mówi CS1647 "przepełnienie stosu w kompilatorze" (gra słów nie jest przeznaczona!). Przyjrzyjmy się bliżej, stwierdziłem, że CodeDom "ładnie" opakowuje ciąg znaków na 80 znaków. To powoduje, że kompilator łączy się z 4193 fragmentami łańcuchów, co najwyraźniej jest głębokością stosu kompilatora C# w x64 NetFx. CSC.exe musi wewnętrznie rekurencyjnie ocenić to wyrażenie, aby "nawodnić" mój pojedynczy ciąg.
Moje pierwsze pytanie brzmi następująco: "czy ktoś wie o obejściu, aby zmienić sposób generowania kodu przez generator kodu?" Nie mogę kontrolować faktu, że system zewnętrzny używa źródła C# jako pośredniego i chcę tego być ciągłym (zamiast ciągłym łączeniem ciągów).
Alternatywnie jak mogę sformułować wyrażenie to tak, że po określonej liczbie znaków, nadal jestem w stanie stworzyć stały, ale składa się z wielu dużej kawałki?
Pełna repro jest tutaj:
// 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);
}
Wersja csc.exe ten przebiega pod wydaje się być 2,0, pomimo kierowania .NET 3.5. – mckamey