Entwickler-Ecke

C# - Die Sprache - Exceptions


kostonstyle - Mi 04.11.09 09:56
Titel: Exceptions
Hallo miteinander
habe eine Frage zu diesen drei Klassen.
Hauptklasse

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
using System;
using System.Net.Mail;

namespace Auswerten_innerer_Ausnahmen
{
   class Program
   {
      static void Main(string[] args)
      {
         Console.Title = "Auswerten innerer Ausnahmen";

         // LogFile (mit einer ungültigen Datei) erzeugen 
         LogFile logFile = null;
         try
         {
            logFile = new LogFile("Y:\\NotExistingFile.txt");
         }
         catch (Exception ex)
         {
            // Die Ausnahmen über die GetExceptionMessages-Erweiterungsmethode
            // auswerten:
            Console.WriteLine(ex.GetExceptionMessages());
         }

         Console.WriteLine();

         // Praxis-Beispiel: Beim Senden einer E-Mail enthält die äußere Exception
         // im Fehlerfall häufig nur die Meldung "Fehler beim Senden von Mail".
         SmtpClient smtpClient = new SmtpClient();
         smtpClient.Host = "mailserver";
         try
         {
            smtpClient.Send("kompendium@juergen-bayer.net""zaphod@galaxy.de",
               "Party""Lust auf eine Party am Ende der Galaxis?");
         }
         catch (Exception ex)
         {
            Console.WriteLine(ex.GetExceptionMessages());
         }

         Console.WriteLine();
         Console.WriteLine("Beenden mit Return");
         Console.ReadLine();
      }
   }
}

In dieser Klasse wird die Ausnahme ausgelöst

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
using System;
using System.IO;

namespace Auswerten_innerer_Ausnahmen
{
   /// <summary>
   /// Klasse zum Protokollieren
   /// </summary>
   public class LogFile : IDisposable
   {
      /// <summary>
      /// Der zum Schreiben verwendete StreamWriter
      /// </summary>
      private System.IO.StreamWriter sw;

      /// <summary>
      /// Der aktuelle Dateiname
      /// </summary>
      private string fileName = null;

      /// <summary>
      /// Konstruktor. Öffnet die Datei.
      /// </summary>
      public LogFile(string fileName)
      {
         this.fileName = fileName;

         try
         {
            this.sw = new System.IO.StreamWriter(fileName, true);
         }
         catch (IOException ex)
         {
            // IOException wird abgefangen und als neue IOException
            // mit neuem Text und innerer Exception weitergegeben
            throw new IOException("Fehler beim Öffnen der Datei '" +
               fileName + "'", ex);
         }
      }

      /// <summary>
      /// Protokolliert eine Info in die Datei 
      /// </summary>
      public void Log(string info)
      {
         try
         {
            this.sw.WriteLine(DateTime.Now.ToString() + ": " +
               info);
         }
         catch (IOException ex)
         {
            // IOException wird abgefangen und als neue IOException
            // mit neuem Text und innerer Exception weitergegeben
            throw new IOException("Fehler beim Schreiben in die Datei '" +
               this.fileName + "'", ex);
         }
      }

      /// <summary>
      /// Gibt die verwendete Datei frei
      /// </summary>
      public void Dispose()
      {
         if (this.sw != null)
         {
            this.sw.Dispose();
         }
      }

      /// <summary>
      /// Ruft Dispose auf
      /// </summary>
      ~LogFile()
      {
         this.Dispose();
      }
   }
}

Die dritte Klasse ist zuständig für die Behandlung von Ausnahmen.

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
using System;
using System.Text.RegularExpressions;

namespace Auswerten_innerer_Ausnahmen
{
   public static class ExceptionExtensions
   {
      ///// <summary>
      ///// Ermittelt die Meldungen der übergebenen und aller inneren Ausnahmen
      ///// </summary>
      ///// <param name="ex">Referenz auf das Exception-Objekt, dessen Meldungen ausgewertet werden sollen</param>
      ///// <returns>Gibt die ermittelten Meldungen durch Zeilenumbrüche getrennt zurück</returns>
      //public static string GetExceptionMessages(this Exception ex)
      //{
      //   // Die Nachricht der aktuellen Exception ermitteln
      //   string messages = ex.Message;

      //   // Die Nachricht(en) der inneren Exception ermitteln
      //   while (ex.InnerException != null)
      //   {
      //      messages += Environment.NewLine + ex.InnerException.Message;
      //      ex = ex.InnerException;
      //   }

      //   // Ergebnis zurückgeben
      //   return messages;
      //}

      /// <summary>
      /// Ermittelt die Meldungen der übergebenen und aller inneren Ausnahmen
      /// </summary>
      /// <param name="ex">Referenz auf das Exception-Objekt, dessen Meldungen ausgewertet werden sollen</param>
      /// <returns>Gibt die ermittelten Meldungen durch Zeilenumbrüche getrennt zurück</returns>
      public static string GetExceptionMessages(this Exception ex)
      {
         string messages = null;

         if (ex is System.Web.HttpException)
         {
            // Bei einer HttpException sollte GetBaseException aufgerufen
            // werden um den zugrundeliegenden Fehler herauszufinden
            ex = ((System.Web.HttpException)ex).GetBaseException();
         }

         // SoapExceptions müssen separat behandelt werden, da diese
         // einen allgemeinen Text, die Nachricht der ursprünglichen
         // Exception und den StackTrace in der Message-Eigenschaft,
         // und leider keine InnerException verwalten.
         if (ex is System.Web.Services.Protocols.SoapException)
         {
            // Nachricht auslesen
            messages = ex.Message;

            // Löschen des einleitenden Textes, der mit ---> beginnt
            int pos1 = messages.IndexOf("--->");
            if (pos1 > -1)
            {
               int pos2 = messages.IndexOf(":", pos1 + 3);
               if (pos2 > -1)
               {
                  messages = messages.Remove(0, pos2 + 1).Trim();
               }
               else
               {
                  messages = messages.Remove(0, pos1 + 4).Trim();
               }
            }

            // Löschen des StackTrace (der mit "\n   " eingeleitet wird)
            Match match = Regex.Match(messages, "\n   ");
            if (match.Success)
            {
               messages = messages.Remove(match.Index,
                  messages.Length - match.Index).Trim();
            }
         }
         else
         {
            // Die Nachricht der aktuellen Exception ermitteln
            messages = ex.Message;

            // Die Nachricht(en) der inneren Exception ermitteln
            if (ex.InnerException != null)
            {
               messages += Environment.NewLine +
                  GetExceptionMessages(ex.InnerException);
            }

            // Überprüfen, ob Nachrichten eventuell mehrfach vorkommen
            string[] messageList = Regex.Split(messages, Environment.NewLine);
            for (int i = 0; i < messageList.Length; i++)
            {
               string message = messageList[i];
               for (int j = i + 1; j < messageList.Length; j++)
               {
                  if (messageList[j] == messageList[i])
                  {
                     messageList[j] = null;
                  }
               }
            }

            // Die übrig gebliebenen Nachrichten wieder zu einem String
            // zusammensetzen
            messages = null;
            for (int i = 0; i < messageList.Length; i++)
            {
               if (messageList[i] != null)
               {
                  if (messages != null)
                  {
                     messages += Environment.NewLine;
                  }
                  messages += messageList[i];
               }
            }
         }

         // Ergebnis zurückgeben
         return messages;
      }
   }
}

Bei diesen Abschnitt hängs bei mir

C#-Quelltext
1:
2:
3:
4:
5:
6:
 catch (Exception ex)
         {
            // Die Ausnahmen über die GetExceptionMessages-Erweiterungsmethode
            // auswerten:
            Console.WriteLine(ex.GetExceptionMessages());
         }

Woher weiss das Objekt ex, dass er die Methode GetExceptionMessages() aufruft, obwohl ex keine Instanz von der Klasse ExceptionExtensions ist?

Gruss kostonstyle


Kha - Mi 04.11.09 14:15

Das Zauberwort steckt hier drin ;) :

C#-Quelltext
1:
public static string GetExceptionMessages(this Exception ex)                    

Extension Methods (C# Programming Guide) [http://msdn.microsoft.com/en-us/library/bb383977.aspx]


kostonstyle - Do 05.11.09 12:01

achso, das ist also eine Erweiterungsmethode.

C#-Quelltext
1:
public static string GetExceptionMessages(this Exception ex)                    

mit this bestimmt man, für welche Klasse die Erweiterung definiert, hier für Exception.
Einfach genial....

Vielen Dank kostonstyle