Обходное решение для C# CodeDom, вызывающего переполнение стека (CS1647) в csc.exe?

Вы можете использовать свойство length:

{% for n in range(yourList| length) %}
       <p class="someclass">{{n + 1}}.</p>
       <a class="someclass2" 
       href="{{ url_for( 'yourFunction', Int = yourList[n].iterable)}}">
       {{yourList[n].iterable}}</a><br>
{% endfor %}

Длина похожа на len (yourlist), который есть у нас в python.

7
задан mckamey 6 June 2009 в 19:47
поделиться

4 ответа

Используя CodeSnippetExpression и строку, заключенную в кавычки, я смог выдать источник, который я хотел бы видеть из Microsoft.CSharp.CSharpCodeGenerator.

Итак, чтобы ответить на вопрос выше замените эту строку:

field.InitExpression = new CodePrimitiveExpression(HugeString);

на это:

field.InitExpression = new CodeSnippetExpression(QuoteSnippetStringCStyle(HugeString));

И, наконец, измените частную строку, цитирующую метод Microsoft.CSharp.CSharpCodeGenerator.QuoteSnippetStringCStyle, чтобы не переносить после 80 символов:

private static string QuoteSnippetStringCStyle(string value)
{
    // CS1647: An expression is too long or complex to compile near '...'
    // happens if number of line wraps is too many (335440 is max for x64, 926240 is max for x86)

    // CS1034: Compiler limit exceeded: Line cannot exceed 16777214 characters
    // theoretically every character could be escaped unicode (6 chars), plus quotes, etc.

    const int LineWrapWidth = (16777214/6) - 4;
    StringBuilder b = new StringBuilder(value.Length+5);

    b.Append("\r\n\"");
    for (int i=0; i<value.Length; i++)
    {
        switch (value[i])
        {
            case '\u2028':
            case '\u2029':
            {
                int ch = (int)value[i];
                b.Append(@"\u");
                b.Append(ch.ToString("X4", CultureInfo.InvariantCulture));
                break;
            }
            case '\\':
            {
                b.Append(@"\\");
                break;
            }
            case '\'':
            {
                b.Append(@"\'");
                break;
            }
            case '\t':
            {
                b.Append(@"\t");
                break;
            }
            case '\n':
            {
                b.Append(@"\n");
                break;
            }
            case '\r':
            {
                b.Append(@"\r");
                break;
            }
            case '"':
            {
                b.Append("\\\"");
                break;
            }
            case '\0':
            {
                b.Append(@"\0");
                break;
            }
            default:
            {
                b.Append(value[i]);
                break;
            }
        }

        if ((i > 0) && ((i % LineWrapWidth) == 0))
        {
            if ((Char.IsHighSurrogate(value[i]) && (i < (value.Length - 1))) && Char.IsLowSurrogate(value[i + 1]))
            {
                b.Append(value[++i]);
            }
            b.Append("\"+\r\n");
            b.Append('"');
        }
    }
    b.Append("\"");
    return b.ToString();
}
4
ответ дан 7 December 2019 в 07:50
поделиться

Итак, я прав, когда говорю, что у вас есть исходный файл C # с чем-то вроде:

public const HugeString = "xxxxxxxxxxxx...." +
    "yyyyy....." +
    "zzzzz.....";

и вы , затем пытаетесь его скомпилировать?

Если да , Я бы попробовал отредактировать текстовый файл (конечно, в коде) перед компиляцией. Это должно быть относительно просто, поскольку, по-видимому, они будут следовать строго определенному шаблону (по сравнению с исходным кодом, созданным человеком). Преобразуйте его, чтобы для каждой константы была одна массивная линия. Дайте мне знать, если вы хотите, чтобы какой-нибудь образец кода попробовал это.

Между прочим, ваше воспроизведение прошло успешно без ошибок на моем компьютере - какую версию фреймворка вы используете? (В моем ящике включена бета-версия 4.0, что может повлиять на ситуацию.)

РЕДАКТИРОВАТЬ: Как насчет того, чтобы изменить ее, чтобы она не была строковой константой? Вам нужно будет разбить его самостоятельно и выдать как общедоступное статическое поле только для чтения, например:

public static readonly HugeString = "xxxxxxxxxxxxxxxx" + string.Empty +
    "yyyyyyyyyyyyyyyyyyy" + string.Empty +
    "zzzzzzzzzzzzzzzzzzz";

Важно, string.Empty - это общедоступное статическое поле только для чтения , не константа. Это означает, что компилятор C # просто вызовет string.Concat , что вполне может быть нормальным. Конечно, это произойдет только один раз во время выполнения - медленнее, чем во время компиляции, но это может быть более простой способ обхода, чем что-либо еще.

2
ответ дан 7 December 2019 в 07:50
поделиться

Я не знаю, как изменить поведение генератора кода, но вы можете изменить размер стека, который использует компилятор, с помощью параметра / stack для EditBin.EXE .

Пример:

editbin /stack:100000,1000 csc.exe <options>

Ниже приведен пример его использования:

class App 
{
    private static long _Depth = 0;

    // recursive function to blow stack
    private static void GoDeep() 
    {
        if ((++_Depth % 10000) == 0) System.Console.WriteLine("Depth is " +
            _Depth.ToString());
        GoDeep();
    return;
    }

    public static void Main() {
        try 
        {
            GoDeep();
        } 
        finally 
        {
        }

        return;
    }
}




editbin /stack:100000,1000 q.exe
Depth is 10000
Depth is 20000

Unhandled Exception: StackOverflowException.

editbin /stack:1000000,1000 q.exe
Depth is 10000
Depth is 20000
Depth is 30000
Depth is 40000
Depth is 50000
Depth is 60000
Depth is 70000
Depth is 80000

Unhandled Exception: StackOverflowException.
0
ответ дан 7 December 2019 в 07:50
поделиться

Обратите внимание, что если вы объявите строку как const, она будет скопирована в каждую сборку, которая использует эту строку в своем коде.

Возможно, вам будет лучше с static readonly.

Другой способ - объявить свойство readonly, которое возвращает строку.

2
ответ дан 7 December 2019 в 07:50
поделиться
Другие вопросы по тегам:

Похожие вопросы: