문제

나는 상황이 필요를 생성하는 등 큰 문자열 const.코드의 원인은 내 생성 CodeDom 나무를 수출하는 C#소스 그리고 나중에 컴파일된 부분으로 큰 어셈블리입니다.

불행하게도,내가 실행하는 상황으로 그것에 의하여하는 경우 이 문자열의 길이를 초과하 335440 문서 Win2K8 64(926240 에 Win2K3x86),C#컴파일러는 종료와 함께 치명적인 오류가:

치명적인 오류가 CS1647:표정이 너무 길거나 복잡한 컴파일 근처'int'

MSDN 말 CS1647 은"스택에서 오버플로우 컴파일러"(웃기려는 의도는 없습니다!).더 자세히 보면 내가 결정하는 CodeDom"잘"랩 내 문자열 const80 습니다.이 컴파일러 연결을 통해 4193 문자열 덩어리를 분명히는 스 깊이의 C#컴파일러에서 64NetFx.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);
}
도움이 되었습니까?

해결책

CodesNipTexpression과 수동으로 인용 된 문자열을 사용하여 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();
}

다른 팁

그래서 나는 당신이 다음과 같은 C# 소스 파일을 가지고 있다고 말하는 것입니다.

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

당신은요 그 다음에 그것을 컴파일하려고?

그렇다면 컴파일하기 전에 텍스트 파일을 코드로 편집하려고합니다. 아마도 엄격하게 정의 된 패턴 (인간 생성 소스 코드와 비교)을 따를 것이므로 비교적 간단해야합니다. 각 상수에 대해 단일 거대한 선이 있도록 변환하십시오. 이것을 시도하기 위해 샘플 코드를 원하는지 알려주세요.

그건 그렇고, 당신의 재현은 내 상자에 오류없이 성공합니다 - 어떤 버전의 프레임 워크를 사용하고 있습니까? (내 상자에는 베타가 4.0 켜져있어 사물에 영향을 줄 수 있습니다.)

편집 : 문자열 상수가 아닌 것을 변경하는 것은 어떻습니까? 당신은 그것을 스스로 분해하고 다음과 같은 공개 정적 독창적 인 필드로 방출해야합니다.

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

결정적으로, string.Empty a public static readonly 필드, ~ 아니다 상수. 즉, C# 컴파일러가 string.Concat 괜찮을 수도 있습니다. 물론 실행 시간에 한 번만 발생합니다. 컴파일 타임에서 수행하는 것보다 느리지 만 다른 어떤 것보다 더 쉬운 인수 일 수 있습니다.

문자열을 const로 선언하면 복사 코드 에서이 문자열을 사용하는 각 어셈블리에서.

정적으로 읽기가 더 좋을 수도 있습니다.

또 다른 방법은 문자열을 반환하는 준비된 속성을 선언하는 것입니다.

코드 생성기의 동작을 변경하는 방법을 모르겠지만 컴파일러가 사용하는 스택 크기를 변경할 수 있습니다. /스택 옵션 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.

는지 확인 응용 프로그램이 수영장에서 IIS 이 32 비트 응용 프로그램을 사용합니다.의 모든것들은 나를 위해 이것을 치료하는 문제를 컴파일하려고 하는 32 비트 응용 프로그램에서 Win7 64 비트입니다.이상(또는지),Microsoft 공급할 수 없게 되는 이 대답이다.의 하루 후기 내용을 발견하려면 이 링크를 수정에는 철도 디자이너 포럼:

http://darrell.mozingo.net/2009/01/17/running-iis-7-in-32-bit-mode/

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top