2012-02-02 8 views
6

Chcę napisać atrybut dla funkcji (lub klasy), która będzie wychwytywać zgłaszany wyjątek i ustawić jego właściwość StackTrace na string.Empty. Jak mogę to zrobić?Jak napisać atrybut przechwytujący wyjątki i usuwa stacktrace?

EDIT:

Jeśli nie mogę tego dokonać w czystym C#, jak mogę to zrobić w C# z PostSharp?

+1

Ciekawy: dlaczego chcesz to zrobić? –

+1

Proszę zobaczyć moją odpowiedź poniżej, choć zniechęciłbym do tego. Wyjątki istnieją z jakiegoś powodu, a to ma pomóc w debugowaniu, gdy się pojawią. Usuwając ślad stosu, skutecznie ukrywasz źródło błędu, którego nie znajdziesz, jeśli nie debugujesz.Jeśli z jakiegoś powodu obawiasz się prywatności, możesz spróbować zaciemnić lub w inny sposób zaszyfrować stos (używając tej samej metody opisanej w odpowiedzi), aby później można ją odszyfrować, powiedzmy z pliku dziennika. –

+0

Jest to również to, czego potrzebuję, a powodem jest to, że muszę przekazać obiekt wyjątku do usługi sieciowej, ale z jakiegoś powodu nie mogę uzyskać usługi, aby go zaakceptować. Mogę więc po prostu przekazać wiadomość i StackTrace, a następnie ponownie utworzyć serwer po stronie wyjątku. – ganders

Odpowiedz

3
[Serializable] 
public class MyAspect: OnExceptionAspect 
{ 
    public override void OnException(MethodExecutionArgs args) 
    { 
     throw new MyCustomException(args.Exception); 
    } 
} 


public class MyCustomException : Exception 
{ 
    public override string StackTrace 
    { 
     get 
     { 
      //return new StackTrace(10).ToString(); //Skip frames 
      return string.Empty; //Return empty string 
     } 
    } 
} 

Musisz rzucić nowy wyjątek. @ Ani przykład po prostu ponownie wyrzuci wyjątek już wyrzucony z tym samym śladem stosu (jest taki sam, ponieważ dostałeś się do tego aspektu). Rzucenie nowego wyjątku "zmieni" ślad stosu, ale go nie usunie. Jeśli chcesz go usunąć, musisz rzucić własną klasę, która przesłania właściwość śledzenia stosu. przekazanie starego wyjątku do nowego wyjątku spowoduje, że stary wyjątek będzie wyjątkiem wewnętrznym (jeśli chcesz)

Możesz to zrobić z PostSharp i bez niego. Klucz jest twoją niestandardową klasą wyjątków.

otrzymuje następujący kod

class Program 
{ 
    static void Main(string[] args) 
    { 
     try 
     { 
      Test1(); 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine(e.StackTrace + Environment.NewLine); 
     } 

     Console.ReadKey(); 
    } 

    private static void Test1() 
    { 
     try 
     { 
      Test2(); 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine(e.StackTrace + Environment.NewLine); 
      throw e; 
     } 
    } 

    private static void Test2() 
    { 
     try 
     { 
      Test3(); 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine(e.StackTrace + Environment.NewLine); 
      throw; 
     } 
    } 

    [MyAspect] 
    private static void Test3() 
    { 
     throw new InvalidOperationException(); 
    } 
} 

[Serializable] 
public class MyAspect : OnExceptionAspect 
{ 
    public override void OnException(MethodExecutionArgs args) 
    { 
     throw args.Exception; 
    } 
} 

wyjście

w ConsoleApplication5.MyAspect.OnException (MethodExecutionArgs args) c: \ t est \ Program.cs: linia 69 na ConsoleApplication5.Program.Test3() w C: \ Test \ Program.cs: wiersz 59
w ConsoleApplication5.Program.Test2() w C: \ Test \ Program.cs: wiersz 47

w ConsoleApplication5.MyAspect.OnException (MethodExecutionArgs ARG) c: \ t \ est program.cs: linia 69 na ConsoleApplication5.Program.Test3() c: \ Test \ Program.cs: linia 59
w ConsoleApplication5.Program.Test2() c: \ test \ Program.cs: linia 52
w ConsoleApplication5.Program.Test1() c: \ \ test Program.cs: linia 34

w ConsoleApplication5.Program .Test1() w C: \ Test \ Program.cs: wiersz 39 w ConsoleApplication5.Program.Main (String [] args) w C: \ Test \ Program.cs: wiersz 19

+1

Czy można to zrobić bez niestandardowej klasy? Na przykład, jeśli chciałbym usunąć ślad stosu wyrzuconego "System.Exception"? – cm007

+0

Możesz używać refleksji, ale naprawdę nie jest to coś, co chcesz robić w produkcji. Mam nadzieję, że to akademickie lub tylko do testowania. Zobacz odpowiedź @hmemcpy. –

+0

W swojej metodzie Test1(), dlaczego robisz "throw e;" zamiast "rzucać;"? – ganders

3

Oryginalny ślad stosu wyjątku jest przechowywany w polu klasy Exception. Jeśli chcesz, aby usunąć go bez tworzenia własnego typ wyjątku, można go usunąć poprzez odbicie tak:

[Serializable] 
public sealed class NoStackTraceException : OnExceptionAspect 
{ 
    public override void OnException(MethodExecutionArgs args) 
    { 
     RemoveStackTrace(args.Exception); 
    } 

    private void RemoveStackTrace(Exception exception) 
    { 
     FieldInfo stackTraceField = typeof(Exception).GetField("_stackTrace", 
      BindingFlags.NonPublic | BindingFlags.Instance); 
     if (stackTraceField != null) 
     { 
      // sets the value of _stackTrace to null 
      stackTraceField.SetValue(exception, null); 
     } 
    } 
} 

Twój wyjątek nie będą już zawierać ślad stosu.

Edit oczywiście można osiągnąć to samo bez PostSharp też, po prostu zrób to w bloku catch.