2013-06-05 11 views
12

Der obige Block bezieht sich auf eine andere Frage + Antwort auf SO enthält keine korrekte Antwort, die hier gilt!Wird eine generische Ausnahme in einem Catch unterstützt?

Ich habe eine Methode für Unit-Tests verwendet. Der Zweck dieser Methode besteht darin, sicherzustellen, dass ein Codeabschnitt (auf den ein Delegat verweist) eine bestimmte Ausnahme auslöst. Wenn diese Ausnahme ausgelöst wird, ist der Komponententest erfolgreich. Wenn keine Ausnahme ausgelöst wird oder eine andere Typausnahme ausgelöst wird, schlägt der Komponententest fehl.

/// <summary> 
/// Checks to make sure that the action throws a exception of type TException. 
/// </summary> 
/// <typeparam name="TException">The type of exception expected.</typeparam> 
/// <param name="action">The code to execute which is expected to generate the exception.</param> 
public static void Throws<TException>(Action action) 
    where TException : Exception 
{ 
    try 
    { 
     action(); 
    } 
    catch (TException) 
    { 
     return; 
    } 
    catch (Exception ex) 
    { 
     Assert.Fail("Wrong exception was thrown. Exception of type " + ex.GetType() + " was thrown, exception of type " + typeof(TException) + " was expected."); 
    } 
    Assert.Fail("No exception was thrown. Exception of type " + typeof(TException) + " was expected."); 
} 

Das soll nächster Aufruf erfolgreich zu sein, aber es funktioniert nicht:

int result = 0; 
Throws<DivideByZeroException>(() => result = result/result); 

Wenn die erwartete Ausnahme des Typs TException geworfen wird, es immer von dem zweiten Fang gefangen wird, nicht durch den ersten Fang. Warum ist das?

Natürlich kann ich ein Workarround mit einem Catch verwenden und testen, ob ex vom Typ TException ist. Ich möchte einfach wissen/verstehen, warum dieser Code kompiliert, aber einfach (nie?) Funktioniert.

EDIT

Auf Wunsch eine "Arbeits" Demo:

using System; 

namespace GenericExceptionDemo 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      int n = 0; 
      Catch<DivideByZeroException>(() => n = n/n); 
     } 

     static public void Catch<TException>(Action action) 
      where TException: Exception 
     { 
      try 
      { 
       action(); 
       Console.WriteLine("No exception thrown. !!!Fail!!!"); 
      } 
      catch (TException) 
      { 
       Console.WriteLine("Expected exception thrown. PASS!"); 
      } 
      catch(Exception ex) 
      { 
       Console.WriteLine("An unexpected exception of type " + ex.GetType() + " thrown. !!!FAIL!!!"); 
      } 
     } 
    } 
} 
+7

Welches Einheitentestframework verwenden Sie? Die meisten haben bereits 'Assert.Throws' ... –

+8

Ihr Code funktioniert für mich ... bitte zeigen Sie ein kurzes aber vollständiges Programm, das das Problem demonstriert. –

+0

Warum soll angegeben werden, dass eine falsche Art von Ausnahme ausgelöst wird? Vielleicht wirft .NET Framework selbst eine System.Drawing.Exception, wenn Sie mit GUIs arbeiten? –

Antwort

2

Du bist nicht die erste Person, um dieses Problem zu begegnen. This question ist sehr ähnlich. Wenn Sie die Antworten und Links durchblättern, kommt es zu einem Fehler in der CLR.

EDIT: Als Follow-up, ich habe Martin laufen Beispiel von VS2010 und bekam folgende Ergebnisse:

  • Targetting .NET 4, PASS
  • Targetting .NET 3.5, FAIL
  • Wenn Sie .NET 3.5 im RELEASE-Modus anvisieren, PASS

Leider sind alle SO-Links zum Microsoft Bug Report jetzt tot und ich konnte keine anderen finden.

+1

Diese vorherige Frage wurde im Jahr 2009 beantwortet, gilt es immer noch? –

+0

Gute Frage. Ich habe nur Martins Code in VS eingefügt (mit kleinen Verbesserungen). Wenn ich .NET 4 anvisiere, funktioniert der Code wie erwartet. Wenn ich 3.5 anvisiere, sehe ich das seltsame Verhalten, das Martin beschrieben hat. –

+0

Es trifft nicht zu. Beide Fragen sind ähnlich, aber die andere Frage hat eine zusätzliche Ausnahmevariable "tex", und die (richtige) Antwort besteht darin, diese Variable zu entfernen. In meinem Fall verwende ich keine Variable, so dass die Antwort für diese Situation nicht gelten kann. –

0

(Dies ist keine konkrete Antwort,., Aber ich konnte es nicht allzu als Kommentar hinterlassen)

ich nicht wiedergeben kann (VS 2012 installiert .NET 4.5, C# 5.0, alle SP).

I definiert sind diese Ausnahmeklasse:

class MyException : Exception 
{ 
    public MyException() { } 
    public MyException(string message) : base(message) { } 
} 

und ein Verfahren:

static void Throws<T>(Action action) where T : Exception 
{ 
    try 
    { 
     action(); 
    } 
    catch (T) { Console.WriteLine("got {0}", typeof(T)); } 
    catch (Exception) { Console.WriteLine("got Exception"); } 
} 

und ich habe es auf diese Weise getestet:

Throws<MyException>(() => { throw new MyException(); }); 

int result = 0; 
Throws<DivideByZeroException>(() => result = result/result); 

und der Ausgang ist:

  • wurde Draft.MyException
  • bekommen System.DivideByZeroException

Also (IMHO) sollten Sie woanders suchen.

Verwandte Themen