Laden...

[ExtensionMethods] generische(!) Exception

Erstellt von ErfinderDesRades vor 15 Jahren Letzter Beitrag vor 15 Jahren 5.306 Views
ErfinderDesRades Themenstarter:in
5.299 Beiträge seit 2008
vor 15 Jahren
[ExtensionMethods] generische(!) Exception

Hi!

Hab grad was erfunden: die generische Exception.
Damit hat man für jede Klasse, die man implementiert, eine spezifische Exception zur Verfügung, ohne Extra-Code schreiben zu müssen.
Und als Extension schreibt sich das Exception-Werfen auch sehr bequem.

namespace System {

   //Extension-Methods für alle Klassen
   public static class ObjectX {
      public static Exception<T> Exception<T>(this T subj, params object[] msgSegments) {
         return new Exception<T>(subj, msgSegments);
      }
   }

   //generische Exception
   public class Exception<T> : System.Exception {

      /// <summary>
      /// stellt den Fehler-Werfer fürs Debuggen zur Verfügung
      /// </summary>
      public readonly T Sender;

      public Exception(T sender, params object[] msgSegments)
         : base(sender.GetType().Name + "-Exception: " + string.Concat(msgSegments)) {
         Sender = sender; 
      }
   }

   //Test-Klasse, die eine generische Exception wirft
   public class CrashTest {
      public void Test(int wrongArgument) {
         throw this.Exception(wrongArgument, " is inappropriate!");
      }
   }

   public class Program {
      //testet typ-spezifisches catchen und natürlich, wie die Ausgabe aussieht
      static void Main(string[] args) {
         try {
            var ct = new CrashTest();
            ct.Test(42);
         }
         catch (Exception<CrashTest> x) {
            // die generische Exception ermöglicht "von Natur aus" typ-spezifisches catchen
            throw;            //re-throwing, um die Ausgabe anzugucken
         }
      }
   }
}


Der frühe Apfel fängt den Wurm.

S
341 Beiträge seit 2008
vor 15 Jahren

Servus und Guten Morgen

Das ist eine schöne sache... kann man sicher nicht nur einmal oder wenig oft gebrauchen vielen dank 😄

Grüße

**Nur die Kenner können mit 10 Fingern bis 1023 zählen !!**
private int Main()
{
   string programmingSkills = getMySkills("programming")
   return = 1;
}
Gelöschter Account
vor 15 Jahren

sollten exceptions nicht ursachenspezifisch benannt sein?

wenn ich eine bl-klasse habe, dann kann die mir nur Exception<klassentyp> werfen. so ist eine selektierung nach ursache und somit eine differenzierte behandlung ausgeschlossen. oder irre ich mich hier?

3.971 Beiträge seit 2006
vor 15 Jahren

leite mal nicht direkt von Exception ab sondern nimm ApplicationException. Microsoft hält sich zwar selbst nicht an sein eigenes Schema Fehler zwischen Anwendung und System/CLR (SystemException) zu trennen, schaden sollte es aber nicht.

Den Fehlertext als params zu anzugeben find ich auch nicht unbedingt das wahre. Ein zusätzlich Nicht-params-Überladung wäre nicht schlecht, sowie einen (oder mehrere Konstruktoren) die auch innerException implementieren.

Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...

Gelöschter Account
vor 15 Jahren

leite mal nicht direkt von Exception ab sondern nimm ApplicationException.

das sollte man wirklich meiden, da die exceptiontabelle innerhalb der clr erst beim schmeißen der entsprechenden exception gebaut wird und hier hat die clr verbundene hände. daher haben die erstmal eingbeaut das er zwecks vererbung erstmal die klasse exception selbst sucht und wenn diese nciht passt (als basistyp) dann geht er alle typen der assembly durch um den passenden basistyp zu finden. das kann recht viel performance kosten beim erstmaligen schmeißen der exception.

0
767 Beiträge seit 2005
vor 15 Jahren

Es gibt auch noch eine Guideline, dass man die ApplicationException nicht verwenden sollte, weil sie unnütz ist:

ApplicationException considered useless

Laut dem Post war sie dazu gedacht Exceptions aus der CLR von eigenen Exceptions unterscheiden zu können. Da die CLR aber teilweise Exceptions wirft die von ApplicationException abgeleitet sind, ist das Unterfangen sinnlos.

loop:
btst #6,$bfe001
bne.s loop
rts

49.485 Beiträge seit 2005
vor 15 Jahren

Hllo kleines_eichhoernchen,

der von dir gegebene Rat entspricht der Empfehlung von Microsoft in .NET 1.0, wurde aber in .NET 2.0 revidiert:

Beachten Sie, dass "Abfangen und Auslösen von Standardausnahmetypen" eine Richtlinie enthält, die bestimmt, dass benutzerdefinierte Ausnahmen nicht von ApplicationException abgeleitet werden sollen. [Nämlich:]

Lösen Sie System.ApplicationException nicht aus, und leiten Sie die Ausnahme nicht ab.

Hallo ErfinderDesRades,

ich fürchte, dein Ansatz geht nicht konform mit dem Empfehlungen von Microsoft, denn:

Lösen Sie nach Möglichkeit die in den System-Namespaces vorhandenen Ausnahmen aus, statt benutzerdefinierte Ausnahmetypen zu erstellen.

herbivore

ErfinderDesRades Themenstarter:in
5.299 Beiträge seit 2008
vor 15 Jahren

@kleines_eichhoernchen

Das mit den params findich grad ziemlich komfortabel. Wie gezeigt, kannich beliebige Argumente mit Text gemischt hineinschmeißen, und er macht das ToString() intern.
Jetzt habichs so:

namespace System {

   //Extension-Methods für alle Klassen
   public static class ObjectX {
      public static Exception<T> Exception<T>(
            this T sender, object firstMsgSegment, params object[] msgSegments) {
         return Exception<T>(sender, null, firstMsgSegment, string.Concat(msgSegments));
      }

      public static Exception<T> Exception<T>(
            this T sender, Exception innerException, params object[] msgSegments) {
         return new Exception<T>(sender, innerException, string.Concat(msgSegments));
      }

      public static Exception<T> Exception<T>(this T sender) {
         return Exception<T>(sender, null);
      }
   }

   /// <summary> generische Exception </summary>
   public class Exception<T> : System.Exception {

      /// <summary> stellt den Fehler-Werfer fürs Debuggen zur Verfügung </summary>
      public readonly T Sender;


      public Exception(T sender, Exception innerException, string message)
         : base(string.Concat(
         sender.GetType().Name,
         "-Exception",
         string.IsNullOrEmpty(message) ? "" : ": " + message),
         innerException) {
         Sender = sender;
      }
   }

   //Test-Klasse, die eine generische Exception wirft
   public class CrashTest {
      public void Test(int wrongArgument) {
         throw this.Exception(wrongArgument, " is inappropriate!");
      }
   }

   public class Program {
      //testet typ-spezifisches catchen und natürlich, wie die Ausgabe aussieht
      static void Main(string[] args) {
         try {
            var ct = new CrashTest();
            ct.Test(42);
         }
         catch (Exception<CrashTest> x) {
            // die generische Exception ermöglicht "von Natur aus" typ-spezifisches catchen
            throw;            //re-throwing, um die Ausgabe anzugucken
         }
      }
   }
}

Also eine generische Exception, die aber mit 3 Extension-Überladungen erzeugt werden kann:*einmal ohne alles *einmal mit beliebig vielen, beliebigen Argumenten - die werden zur Meldung verkettet *einmal mit InnerException + beliebigen Meldungs-Segmenten

Ah! - Zwischen posts -

Lösen Sie nach Möglichkeit die in den System-Namespaces vorhandenen Ausnahmen aus, statt benutzerdefinierte Ausnahmetypen zu erstellen.

Wieso hat TryCatch dann dieses Feature, dass der Catch-Block genau nach Exception-Typ differenzieren kann - wenn man dann doch nur Standard-Exceptions auslösen soll?
Das scheint mir doch sehr nützlich für eine differenzierte Fehlerbehandlung.

Die sind ja auch iwi lustig: Erst selbst hunderte von Exceptions erfinden, für alle möglichen Belange, und dann empfehlen, keine weiteren zu erfinden, für eigene Belange!

Vonne Intention her ist die generische Exception ja eigentlich gar nicht mal so konträr zur zitierten Empfehlung: Weil sie hilft ja, mit wenigen Exception-Typen auszukommen, und bietet trotzdem eine hohe Differenzierung.

Kann mir gut vorstellen, daß inne nächsten Version auchn paar generische Exceptions enthalten sind, vergleicbar mit dem generischen Eventhandler, der ja auch einen wahren Eventhandler-Delegaten-Dschungel aufräumt, oder den generischen Actions und Funcs, die ja im Grunde jeden Delegaten emulieren können.

Der frühe Apfel fängt den Wurm.

5.658 Beiträge seit 2006
vor 15 Jahren

Wieso hat TryCatch dann dieses Feature, dass der Catch-Block genau nach Exception-Typ differenzieren kann - wenn man dann doch nur Standard-Exceptions auslösen soll?

Weil es ja auch verschiedene "Standard"-Exceptions gibt. Allerdings sind die nach Art des Fehlers gegliedert und nicht nach den auslösenden Objekten, z.B. ArgumentNull, OutOfRange, NotImplemented etc.

Wenn dein Objekt eine bestimmte neue Art von Fehlern erzeugt, baust du dir nach dem gleichen Schema eigene Exception-Klassen, wie es auch von Microsoft gemacht wird, z.B. DirectXException usw. usf.

Ich verstehe also nicht, wozu deine Klasse gut sein soll. Vielleicht willst du auch deinem Namen alle Ehre machen und das Rad neu erfinden...?

Schöne Grüße,
Christian

Weeks of programming can save you hours of planning

49.485 Beiträge seit 2005
vor 15 Jahren

Hallo ErfinderDesRades,

Wieso hat TryCatch dann dieses Feature, dass der Catch-Block genau nach Exception-Typ differenzieren kann - wenn man dann doch nur Standard-Exceptions auslösen soll?

Das sollten wir bitte nicht hier bei den Snippets ausdiskutieren. Deshalb nur soviel: Die Aussagen von MS ist "benutzerdefinierte Ausnahmetypen nach **Möglichkeit **zu vermeiden". Wenn sich eine Differenzierung anbietet, wären eigene Exceptions also in Ordnung. Aber selbst dann sollte die Differenzierung nach der Art der Ausnahme erfolgen und sicher nicht nach der Klasse, die die Ausnahme wirft, wie das bei deinem Snippet der Fall ist.

Die sind ja auch iwi lustig: Erst selbst hunderte von Exceptions erfinden, für alle möglichen Belange, und dann empfehlen, keine weiteren zu erfinden, für eigene Belange!

Gerade weil es schon für soviele Belange Ausnahmen gibt, wird man kaum in die Situationen kommen, in denen man eigene Exceptions braucht. Daher ist die Empfehlung in meinen Augen voll gerechtfertigt und dein Snippet geht nun mal leider nicht konform damit.

herbivore