문제

현재 이 문제가 발생하지 않습니다., 하지만 당신은 결코 알지 못하며 사고 실험은 항상 재미있습니다.

이를 시도하기 위해 아키텍처에서 발생해야 하는 명백한 문제를 무시합니다., 다른 사람의 디자인에 대해 끔찍하게 작성된 코드가 있고 동일한 코드 블록에서 광범위하고 다양한 작업을 수행해야 한다고 가정해 보겠습니다. 예:

WidgetMaker.SetAlignment(57);
contactForm["Title"] = txtTitle.Text;
Casserole.Season(true, false);
((RecordKeeper)Session["CasseroleTracker"]).Seasoned = true;

100을 곱합니다.이들 중 일부는 효과가 있을 수도 있고 다른 일부는 심하게 잘못될 수도 있습니다.필요한 것은 "오류 발생 시 다음 재개"에 해당하는 C#입니다. 그렇지 않으면 여러 줄의 코드 주위에 try-catch를 복사하여 붙여넣게 됩니다.

이 문제를 어떻게 해결하려고 하시나요?

도움이 되었습니까?

해결책

VB.NET에서 코드를 작성한다는 것은 매우 분명합니다. 오류 발생 시 다음 재개, DLL에서 C#으로 내보냅니다.다른 것은 단지 처벌에 대한 멍청이입니다.

다른 팁

public delegate void VoidDelegate();

public static class Utils
{
  public static void Try(VoidDelegate v) {
    try {
      v();
    }
    catch {}
  }
}

Utils.Try( () => WidgetMaker.SetAlignment(57) );
Utils.Try( () => contactForm["Title"] = txtTitle.Text );
Utils.Try( () => Casserole.Season(true, false) );
Utils.Try( () => ((RecordKeeper)Session["CasseroleTracker"]).Seasoned = true );

개별적이고 이름이 잘 알려진 메서드로 리팩토링합니다.

AdjustFormWidgets();
SetContactTitle(txtTitle.Text);
SeasonCasserole();

이들 각각은 적절하게 보호됩니다.

내가 말할 것 아무것도하지 마세요.

네 맞습니다. 아무것도 하지 마세요.

당신은 나에게 두 가지 사실을 분명히 밝혔습니다.

  1. 당신은 아키텍처가 지루하다는 것을 알고 있습니다.
  2. 이런 쓰레기가 엄청나게 많습니다.

내가 말하다:

  • 아무것도하지 마세요.
  • 오류가 발생할 때마다 이메일을 보내도록 전역 오류 처리기를 추가하세요.
  • 무언가가 넘어질 때까지(또는 테스트에 실패할 때까지) 기다리세요.
  • 이를 수정하십시오(필요에 따라 리팩토링 페이지 범위 내에서).
  • 문제가 발생할 때마다 반복합니다.

상황이 그렇게 나쁘다면 곧 해결될 것입니다.예, 기분 나쁘게 들리고 처음부터 버그 수정으로 머리가 빠지는 일이 있을 수도 있지만 그렇게 하면 가능합니다. 필요하거나 버그가 있는 코드를 수정하기 전에 (큰) 양 실제로 작동할 수 있는 코드 아무리 보기 흉해도 말이죠.

일단 전쟁에서 승리하기 시작하면 코드를 더 잘 다룰 수 있게 되며(모든 리팩토링으로 인해) 승리하는 디자인에 대한 더 나은 아이디어를 갖게 됩니다.

모든 것을 버블랩으로 포장하려고 하면 아마도 시간이 오래 걸릴 것이며 여전히 문제를 해결하는 데 더 이상 가까워지지 않을 것입니다.

빠른 실패

자세히 설명하자면 질문에 의문을 제기하는 것 같습니다.예외가 발생하면 아무 일도 일어나지 않은 것처럼 코드가 계속 진행되기를 원하는 이유는 무엇입니까?특정 상황에서 예외가 발생할 것으로 예상하는 경우 해당 코드 주위에 try-catch 블록을 작성하여 처리하거나, 예상치 못한 오류가 발생하는 경우 애플리케이션을 중단하거나 재시도하거나 실패하는 것이 좋습니다.부상당한 좀비가 '뇌'라고 신음하는 것처럼 계속하지 마십시오.

이것은 전처리기를 갖는 것이 유용한 것 중 하나입니다.예외를 삼키는 매크로를 정의한 다음 빠른 스크립트를 사용하여 해당 매크로를 모든 줄에 추가할 수 있습니다.

따라서 이것이 C++이라면 다음과 같이 할 수 있습니다.

#define ATTEMPT(x) try { x; } catch (...) { }
// ...
ATTEMPT(WidgetMaker.SetAlignment(57));
ATTEMPT(contactForm["Title"] = txtTitle.Text);
ATTEMPT(Casserole.Season(true, false));
ATTEMPT(((RecordKeeper)Session["CasseroleTracker"]).Seasoned = true);

불행하게도 C/C++처럼 전처리기를 포함하는 언어는 많지 않은 것 같습니다.

자신만의 전처리기를 생성하여 사전 빌드 단계로 추가할 수 있습니다.완전히 자동화하고 싶다면 실제 코드 파일을 가져와 자체적으로 try/catch 항목을 추가하는 전처리기를 작성할 수 있습니다(따라서 해당 ATTEMPT() 블록을 코드에 수동으로 추가할 필요가 없습니다). .예상되는 라인만 수정했는지 확인하는 것은 어려울 수 있습니다(빌드를 중단하지 않으려면 변수 선언, 루프 구성 등을 건너뛰어야 함).

그런데 이런 생각은 정말 끔찍한 생각이고 절대로 해서는 안 될 일이라고 생각하는데 질문이 생겼습니다.:)

정말, 절대 이러면 안 됩니다.오류의 원인을 찾아 수정해야 합니다.오류를 삼키거나 무시하는 것은 나쁜 행동이므로 옳은 여기서 대답은 "버그를 수정하세요. 무시하지 마세요!"입니다.:)

On Error Resume Next C# 세계에서는 정말 나쁜 생각입니다.또한 다음과 같은 것을 추가하지도 않을 것입니다. On Error Resume Next 실제로 당신을 도와주세요.그렇게 하면 더 미묘한 오류, 데이터 손실 및 데이터 손상 가능성이 발생할 수 있는 나쁜 상태에 빠지게 됩니다.

그러나 질문자에게 답변을 제공하려면 전역 처리기를 추가하고 TargetSite를 확인하여 어떤 메서드가 중단되었는지 확인할 수 있습니다.그러면 적어도 그것이 어떤 라인에서 중단되었는지 알 수 있습니다.다음 부분은 디버거와 동일한 방식으로 "다음 문"을 설정하는 방법을 알아내는 것입니다.이 시점에서 스택이 풀리지 않거나 다시 생성할 수 있기를 바라지만 확실히 시도해 볼 가치가 있습니다.그러나 이 접근 방식을 사용하면 디버그 기호가 포함되도록 코드를 매번 디버그 모드에서 실행해야 합니다.

누군가 언급했듯이 VB에서는 이것을 허용합니다.C#에서도 같은 방식으로 하면 어떨까요?신뢰할 수 있는 반사경 입력:

이것:

Sub Main()
    On Error Resume Next

    Dim i As Integer = 0

    Dim y As Integer = CInt(5 / i)


End Sub

다음과 같이 번역됩니다.

public static void Main()
{
    // This item is obfuscated and can not be translated.
    int VB$ResumeTarget;
    try
    {
        int VB$CurrentStatement;
    Label_0001:
        ProjectData.ClearProjectError();
        int VB$ActiveHandler = -2;
    Label_0009:
        VB$CurrentStatement = 2;
        int i = 0;
    Label_000E:
        VB$CurrentStatement = 3;
        int y = (int) Math.Round((double) (5.0 / ((double) i)));
        goto Label_008F;
    Label_0029:
        VB$ResumeTarget = 0;
        switch ((VB$ResumeTarget + 1))
        {
            case 1:
                goto Label_0001;

            case 2:
                goto Label_0009;

            case 3:
                goto Label_000E;

            case 4:
                goto Label_008F;

            default:
                goto Label_0084;
        }
    Label_0049:
        VB$ResumeTarget = VB$CurrentStatement;
        switch (((VB$ActiveHandler > -2) ? VB$ActiveHandler : 1))
        {
            case 0:
                goto Label_0084;

            case 1:
                goto Label_0029;
        }
    }
    catch (object obj1) when (?)
    {
        ProjectData.SetProjectError((Exception) obj1);
        goto Label_0049;
    }
Label_0084:
    throw ProjectData.CreateProjectError(-2146828237);
Label_008F:
    if (VB$ResumeTarget != 0)
    {
        ProjectData.ClearProjectError();
    }
}

코드를 다시 작성하세요.논리적으로 서로 의존하는 일련의 명령문을 찾아 하나가 실패하면 다음 명령문이 의미가 없도록 하고, 결과를 무시하려면 해당 명령문을 자체 함수에 포함시키고 그 주위에 try-catch를 두십시오. 그걸 계속하세요.

이는 가장 문제가 많은 부분을 식별하는 데 도움이 될 수 있습니다.

@ JB King을 상기시켜 주셔서 감사합니다.로깅 애플리케이션 블록에는 이벤트를 추적하는 데 사용할 수 있는 계측 이벤트가 있습니다. MS Enterprise 라이브러리 문서에서 자세한 정보를 찾을 수 있습니다.

Using (New InstEvent)
<series of statements> 
End Using

이 사용의 모든 단계는 로그 파일로 추적되며 이를 구문 분석하여 로그가 중단된 위치(ex가 발생함)를 확인하고 주요 위반자를 식별할 수 있습니다.

리팩토링은 실제로 최선의 방법이지만, 리팩토링이 많은 경우 최악의 범죄자를 찾아내는 데 도움이 될 수 있습니다.

~할 수 있었다 goto를 사용하지만 여전히 지저분합니다.

나는 실제로 한동안 일종의 단일 명령문 try-catch를 원했습니다.로깅 코드를 추가하거나 실패할 경우 기본 프로그램 흐름을 중단하고 싶지 않은 특정 경우에 도움이 될 수 있습니다.

linq와 관련된 일부 기능을 사용하여 뭔가 작업을 수행할 수 있을 것으로 생각되지만 지금은 이를 조사할 시간이 없습니다.명령문을 익명 함수로 래핑하는 방법을 찾을 수 있다면 다른 함수를 사용하여 try-catch 블록 내에서 호출하면 작동할 것입니다.하지만 그것이 가능한지는 아직 확실하지 않습니다.

컴파일러가 이 코드에 대한 식 트리를 제공하도록 할 수 있는 경우 각 문을 원래 문을 래핑하는 새로운 try-catch 블록으로 바꿔 해당 식 트리를 수정할 수 있습니다.이것은 들리는 것만큼 터무니없는 것은 아닙니다.LINQ의 경우 C#에서는 람다 식을 런타임 시 사용자 코드에서 조작할 수 있는 식 트리로 캡처하는 기능을 획득했습니다.

System.Linq.Expressions에 "try" 문이 없다는 이유 외에는 다른 이유가 없다면 현재 .NET 3.5에서는 이 접근 방식을 사용할 수 없습니다.그러나 DLR 및 LINQ 식 트리의 병합이 완료되면 C#의 향후 버전에서는 실행 가능할 수도 있습니다.

C#에서 리플렉션을 사용하지 않는 이유는 무엇입니까?코드를 반영하는 클래스를 만들고 각 개별 try/catch 블록에 무엇을 넣을지에 대한 힌트로 행 번호를 사용할 수 있습니다.여기에는 몇 가지 장점이 있습니다.

  1. 소스 코드를 엉망으로 만들 필요가 없고 디버그 모드에서만 사용할 수 있으므로 약간 덜 추악합니다.
  2. C#을 구현하는 동안 C#에 대해 흥미로운 점을 배웁니다.

그러나 물론 당신이 다른 작업의 유지 관리를 맡거나 예외를 처리하여 수정할 수 있어야 하는 경우를 제외하고는 이 중 어떤 것도 반대하는 것이 좋습니다.그래도 글을 쓰는 것은 재미있을 것입니다.

재미있는 질문입니다.매우 끔찍합니다.

매크로를 활용하시면 좋을 것 같습니다.그러나 이것은 C#이므로 일부 전처리기 작업이나 외부 도구를 사용하여 라인을 개별 try-catch 블록으로 래핑하여 문제를 해결할 수 있습니다.당신이 원하지 않았다는 뜻인지 확실하지 않습니다 수동으로 포장하거나 try-catch를 피하고 싶었던 것 전적으로.

이 문제를 해결하면서 나는 모든 줄에 라벨을 붙이고 운이 좋지 않은 한 번의 캐치에서 뒤로 물러나려고 했습니다.하지만, 크리스토퍼는 이를 수행하는 올바른 방법을 발견했습니다..좀 있어요 Dot Net Thoughts에서 이에 대한 흥미로운 추가 토론이 이루어졌습니다. 그리고 에 Mike Stall의 .NET 블로그.

편집하다:물론.그만큼 try-catch / switch-goto 나열된 솔루션은 실제로 컴파일되지 않습니다. try 라벨이 범위를 벗어났습니다. catch.이런 컴파일을 만들기 위해 무엇이 빠졌는지 아는 사람이 있나요?

컴파일러 전처리 단계를 통해 이를 자동화하거나 해킹할 수도 있습니다. Mike Stall의 인라인 IL 도구 오류 무지를 주입합니다.

(예외 조사에 대한 Orion Adrian의 답변 다음 명령을 설정하는 것도 흥미롭습니다.)

전체적으로 보면 흥미롭고 유익한 운동인 것 같습니다.물론 ON ERROR RESUME NEXT를 시뮬레이션하는 노력이 코드를 수정하는 노력보다 더 큰 시점을 결정해야 합니다.:-)

오류를 잡아라. 처리되지 않은 예외 이벤트 응용 프로그램의.이렇게 하면 처리되지 않은 예외가 보낸 사람 및 개발자가 합리적으로 판단하는 기타 정보에 대해 기록될 수도 있습니다.

불행히도 당신은 아마도 운이 좋지 않을 것입니다.On Error Resume Next는 일반적으로 크게 권장되지 않는 레거시 옵션이며 C#에 대한 내 지식과 동일하지 않습니다.

코드를 VB에 남겨두고(OnError ResumeNext에 대한 특정 요청을 고려할 때 소스인 것 같습니다) 필요한 새 코드를 구현하는 C# dll 또는 exe와 인터페이스하는 것이 좋습니다.그런 다음 코드를 안전하게 만들기 위해 리팩토링을 수행하고 이 작업을 수행하면서 이 안전한 코드를 C#으로 변환합니다.

처리되지 않은 예외를 처리하는 방법에 대한 한 가지 아이디어를 얻으려면 Enterprise Library의 예외 처리 구성 요소를 통합하는 것을 살펴볼 수 있습니다.

ASP.Net 응용 프로그램의 경우 Global.asax에 "Application_Error"라는 함수가 있는데, 이 함수는 대부분의 경우 호출되며 일반적으로 치명적인 오류는 다른 경우에 발생합니다.

이 일을 피하고 싶은 모든 이유를 무시하고......

단순히 줄 수를 줄여야 한다면 다음과 같이 시도해 볼 수 있습니다.

int totalMethodCount = xxx;
for(int counter = 0; counter < totalMethodCount; counter++) {
    try {
        if (counter == 0) WidgetMaker.SetAlignment(57);
        if (counter == 1) contactForm["Title"] = txtTitle.Text;
        if (counter == 2) Casserole.Season(true, false);
        if (counter == 3) ((RecordKeeper)Session["CasseroleTracker"]).Seasoned = true;
    } catch (Exception ex) {
        // log here
    }
}

그러나 호출 결과를 재사용하려는 경우 변수 범위를 주의 깊게 관찰해야 합니다.

각 줄을 한 번에 하나씩 'Try/catch로 둘러싸기'로 Hilite합니다.그것은 당신이 언급한 복사 붙여넣기를 피합니다

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