2008-05-14 Andreas Nahr <ClassDevelopment@A-SoftTech.com>
[mono.git] / mcs / class / corlib / System / Exception.cs
1 //
2 // System.Exception.cs
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //   Patrik Torstensson
7 //
8 // (C) Ximian, Inc.  http://www.ximian.com
9 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30
31 using System.Collections;
32 using System.Diagnostics;
33 using System.Reflection;
34 using System.Text;
35 using System.Runtime.InteropServices;
36 using System.Runtime.CompilerServices;
37 using System.Runtime.Serialization;
38 using System.Security.Permissions;
39
40 namespace System
41 {
42         [Serializable]
43 #if NET_2_0
44         [ComVisible(true)]
45         [ComDefaultInterface (typeof (_Exception))]
46         [ClassInterface (ClassInterfaceType.None)]
47 #else
48         [ClassInterface (ClassInterfaceType.AutoDual)]
49 #endif
50         public class Exception : ISerializable 
51 #if NET_2_0
52         , _Exception
53 #endif
54         {
55                 #region Sync with object-internals.h
56                 IntPtr [] trace_ips;
57                 Exception inner_exception;
58                 internal string message;
59                 string help_link;
60                 string class_name;
61                 string stack_trace;
62                 string remote_stack_trace;
63                 int remote_stack_index;
64                 internal int hresult = unchecked ((int)0x80004005);
65                 string source;
66                 private IDictionary _data;
67                 #endregion
68
69                 public Exception ()
70                 {
71                 }
72
73                 public Exception (string message)
74                 {
75                         this.message = message;
76                 }
77
78                 protected Exception (SerializationInfo info, StreamingContext context)
79                 {
80                         if (info == null)
81                                 throw new ArgumentNullException ("info");
82
83                         class_name          = info.GetString ("ClassName");
84                         message             = info.GetString ("Message");
85                         help_link           = info.GetString ("HelpURL");
86                         stack_trace         = info.GetString ("StackTraceString");
87                         remote_stack_trace  = info.GetString ("RemoteStackTraceString");
88                         remote_stack_index  = info.GetInt32  ("RemoteStackIndex");
89                         hresult             = info.GetInt32  ("HResult");
90                         source              = info.GetString ("Source");
91                         inner_exception     = (Exception) info.GetValue ("InnerException", typeof (Exception));
92                 }
93
94                 public Exception (string message, Exception innerException)
95                 {
96                         inner_exception = innerException;
97                         this.message = message;
98                 }
99
100                 public Exception InnerException {
101                         get { return inner_exception; }
102                 }
103
104                 public virtual string HelpLink {
105                         get { return help_link; }
106                         set { help_link = value; }
107                 }
108
109                 protected int HResult {
110                         get { return hresult; }
111                         set { hresult = value; }
112                 }
113
114                 internal void SetMessage (string s)
115                 {
116                         message = s;
117                 }
118
119                 internal void SetStackTrace (string s)
120                 {
121                         stack_trace = s;
122                 }
123
124                 public virtual string Message {
125                         get {
126                                 if (message == null)
127 #if NET_2_0
128                                         message = string.Format (Locale.GetText ("Exception of type '{0}' was thrown."),
129 #else
130                                         message = string.Format (Locale.GetText ("Exception of type {0} was thrown."),
131 #endif
132                                                 GetType ().ToString());
133
134                                 return message;
135                         }
136                 }
137
138                 public virtual string Source {
139 #if ONLY_1_1
140                         [ReflectionPermission (SecurityAction.Assert, TypeInformation = true)]
141 #endif
142                         get {
143                                 if (source == null) {
144                                         StackTrace st = new StackTrace (this, true);
145                                         if (st.FrameCount > 0) {
146                                                 StackFrame sf = st.GetFrame (0);
147                                                 if (st != null) {
148                                                         MethodBase method = sf.GetMethod ();
149                                                         if (method != null) {
150                                                                 source = method.DeclaringType.Assembly.UnprotectedGetName ().Name;
151                                                         }
152                                                 }
153                                         }
154                                 }
155
156                                 // source can be null
157                                 return source;
158                         }
159
160                         set {
161                                 source = value;
162                         }
163                 }
164
165                 public virtual string StackTrace {
166                         get {
167                                 if (stack_trace == null) {
168                                         if (trace_ips == null)
169                                                 /* Not thrown yet */
170                                                 return null;
171
172                                         StackTrace st = new StackTrace (this, 0, true, true);
173
174                                         StringBuilder sb = new StringBuilder ();
175
176                                         string newline = String.Format ("{0}  {1} ", Environment.NewLine, Locale.GetText ("at"));
177                                         string unknown = Locale.GetText ("<unknown method>");
178
179                                         for (int i = 0; i < st.FrameCount; i++) {
180                                                 StackFrame frame = st.GetFrame (i);
181                                                 if (i == 0)
182                                                         sb.AppendFormat ("  {0} ", Locale.GetText ("at"));
183                                                 else
184                                                         sb.Append (newline);
185
186                                                 if (frame.GetMethod () == null) {
187                                                         string internal_name = frame.GetInternalMethodName ();
188                                                         if (internal_name != null)
189                                                                 sb.Append (internal_name);
190                                                         else
191                                                                 sb.AppendFormat ("<0x{0:x5}> {1}", frame.GetNativeOffset (), unknown);
192                                                 } else {
193                                                         sb.Append (GetFullNameForStackTrace (frame.GetMethod ()));
194
195                                                         if (frame.GetILOffset () == -1)
196                                                                 sb.AppendFormat (" <0x{0:x5}> ", frame.GetNativeOffset ());
197                                                         else
198                                                                 sb.AppendFormat (" [0x{0:x5}] ", frame.GetILOffset ());
199
200                                                         string fileName = frame.GetFileName ();
201                                                         if (fileName != null)
202                                                                 sb.AppendFormat ("in {0}:{1} ", fileName, frame.GetFileLineNumber ());
203                                                         }
204                                         }
205                                         stack_trace = sb.ToString ();
206                                 }
207
208                                 return stack_trace;
209                         }
210                 }
211
212                 public MethodBase TargetSite {
213 #if ONLY_1_1
214                         [ReflectionPermission (SecurityAction.Demand, TypeInformation = true)]
215 #endif
216                         get {
217                                 StackTrace st = new StackTrace (this, true);
218                                 if (st.FrameCount > 0)
219                                         return st.GetFrame (0).GetMethod ();
220                                 
221                                 return null;
222                         }
223                 }
224
225 #if NET_2_0
226                 public virtual IDictionary Data {
227                         get {
228                                 if (_data == null) {
229                                         // default to empty dictionary
230                                         _data = (IDictionary) new Hashtable ();
231                                 }
232                                 return _data;
233                         }
234                 }
235 #endif
236
237                 public virtual Exception GetBaseException ()
238                 {
239                         Exception inner = inner_exception;
240                                 
241                         while (inner != null)
242                         {
243                                 if (inner.InnerException != null)
244                                         inner = inner.InnerException;
245                                 else
246                                         return inner;
247                         }
248
249                         return this;
250                 }
251
252 #if ONLY_1_1
253                 [ReflectionPermission (SecurityAction.Assert, TypeInformation = true)]
254 #endif
255                 [SecurityPermission (SecurityAction.LinkDemand, SerializationFormatter = true)]
256                 public virtual void GetObjectData (SerializationInfo info, StreamingContext context)
257                 {
258                         if (info == null)
259                                 throw new ArgumentNullException ("info");
260
261                         if (class_name == null)
262                                 class_name = GetType ().FullName;
263
264                         info.AddValue ("ClassName", class_name);
265                         info.AddValue ("Message", message);
266                         info.AddValue ("InnerException", inner_exception);
267                         info.AddValue ("HelpURL", help_link);
268                         info.AddValue ("StackTraceString", StackTrace);
269                         info.AddValue ("RemoteStackTraceString", remote_stack_trace);
270                         info.AddValue ("RemoteStackIndex", remote_stack_index);
271                         info.AddValue ("HResult", hresult);
272                         info.AddValue ("Source", Source);
273                         info.AddValue ("ExceptionMethod", null);
274                 }
275
276 #if ONLY_1_1
277                 [ReflectionPermission (SecurityAction.Assert, TypeInformation = true)]
278 #endif
279                 public override string ToString ()
280                 {
281                         System.Text.StringBuilder result = new System.Text.StringBuilder (this.GetType ().FullName);
282                         result.Append (": ").Append (Message);
283
284                         if (null != remote_stack_trace)
285                                 result.Append (remote_stack_trace);
286                                 
287                         if (inner_exception != null) 
288                         {
289                                 result.Append (" ---> ").Append (inner_exception.ToString ());
290                                 result.Append (Environment.NewLine);
291                                 result.Append (Locale.GetText ("--- End of inner exception stack trace ---"));
292                         }
293
294                         if (StackTrace != null)
295                                 result.Append (Environment.NewLine).Append (StackTrace);
296                         return result.ToString();
297                 }
298
299                 internal Exception FixRemotingException ()
300                 {
301                         string message = (0 == remote_stack_index) ?
302                                 Locale.GetText ("{0}{0}Server stack trace: {0}{1}{0}{0}Exception rethrown at [{2}]: {0}") :
303                                 Locale.GetText ("{1}{0}{0}Exception rethrown at [{2}]: {0}");
304                         string tmp = String.Format (message, Environment.NewLine, StackTrace, remote_stack_index);
305
306                         remote_stack_trace = tmp;
307                         remote_stack_index++;
308
309                         stack_trace = null;
310
311                         return this;
312                 }
313
314                 internal string GetFullNameForStackTrace (MethodBase mi)
315                 {
316                         string parms = String.Empty;
317                         ParameterInfo[] p = mi.GetParameters ();
318                         for (int i = 0; i < p.Length; ++i) {
319                                 if (i > 0)
320                                         parms = parms + ", ";
321                                 string paramName = (p [i].Name == null) ? String.Empty : (" " + p [i].Name);
322                                 Type pt = p[i].ParameterType;
323                                 if (pt.IsClass && pt.Namespace != String.Empty)
324                                         parms = parms + pt.Namespace + "." + pt.Name + paramName;
325                                 else
326                                         parms = parms + pt.Name + paramName;
327                         }
328
329                         string generic = String.Empty;
330 #if NET_2_0 || BOOTSTRAP_NET_2_0
331                         if (mi.IsGenericMethod) {
332                                 Type[] gen_params = mi.GetGenericArguments ();
333                                 generic = "[";
334                                 for (int j = 0; j < gen_params.Length; j++) {
335                                         if (j > 0)
336                                                 generic += ",";
337                                         generic += gen_params [j].Name;
338                                 }
339                                 generic += "]";
340                         }
341 #endif
342                         return mi.DeclaringType.ToString () + "." + mi.Name + generic + " (" + parms + ")";
343                 }
344
345 #if NET_2_0
346                 //
347                 // The documentation states that this is available in 1.x,
348                 // but it was not available (MemberRefing this would fail)
349                 // and it states the signature is `override sealed', but the
350                 // correct value is `newslot' 
351                 //
352                 public new Type GetType ()
353                 {
354                         return base.GetType ();
355                 }
356 #endif
357         }
358 }