a47c670b31af5841940e2119a8155f4747e7b440
[mono.git] / mcs / class / referencesource / mscorlib / system / throwhelper.cs
1 // ==++==
2 // 
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 // 
5 // ==--==
6
7 namespace System {
8     // This file defines an internal class used to throw exceptions in BCL code.
9     // The main purpose is to reduce code size. 
10     // 
11     // The old way to throw an exception generates quite a lot IL code and assembly code.
12     // Following is an example:
13     //     C# source
14     //          throw new ArgumentNullException("key", Environment.GetResourceString("ArgumentNull_Key"));
15     //     IL code:
16     //          IL_0003:  ldstr      "key"
17     //          IL_0008:  ldstr      "ArgumentNull_Key"
18     //          IL_000d:  call       string System.Environment::GetResourceString(string)
19     //          IL_0012:  newobj     instance void System.ArgumentNullException::.ctor(string,string)
20     //          IL_0017:  throw
21     //    which is 21bytes in IL.
22     // 
23     // So we want to get rid of the ldstr and call to Environment.GetResource in IL.
24     // In order to do that, I created two enums: ExceptionResource, ExceptionArgument to represent the
25     // argument name and resource name in a small integer. The source code will be changed to 
26     //    ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key, ExceptionResource.ArgumentNull_Key);
27     //
28     // The IL code will be 7 bytes.
29     //    IL_0008:  ldc.i4.4
30     //    IL_0009:  ldc.i4.4
31     //    IL_000a:  call       void System.ThrowHelper::ThrowArgumentNullException(valuetype System.ExceptionArgument)
32     //    IL_000f:  ldarg.0
33     //
34     // This will also reduce the Jitted code size a lot. 
35     //
36     // It is very important we do this for generic classes because we can easily generate the same code 
37     // multiple times for different instantiation. 
38     // 
39     // <
40
41
42
43
44
45
46
47
48
49     using System.Runtime.CompilerServices;        
50     using System.Runtime.Serialization;
51     using System.Diagnostics.Contracts;
52
53     [Pure]
54     internal static class ThrowHelper {    
55         internal static void ThrowArgumentOutOfRangeException() {        
56             ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_Index);            
57         }
58
59         internal static void ThrowWrongKeyTypeArgumentException(object key, Type targetType) {
60             throw new ArgumentException(Environment.GetResourceString("Arg_WrongType", key, targetType), "key");
61         }
62
63         internal static void ThrowWrongValueTypeArgumentException(object value, Type targetType) {
64             throw new ArgumentException(Environment.GetResourceString("Arg_WrongType", value, targetType), "value");
65         }
66
67         internal static void ThrowKeyNotFoundException() {
68             throw new System.Collections.Generic.KeyNotFoundException();
69         }
70         
71         internal static void ThrowArgumentException(ExceptionResource resource) {
72             throw new ArgumentException(Environment.GetResourceString(GetResourceName(resource)));
73         }
74
75         internal static void ThrowArgumentException(ExceptionResource resource, ExceptionArgument argument) {
76             throw new ArgumentException(Environment.GetResourceString(GetResourceName(resource)), GetArgumentName(argument));
77         }
78
79         internal static void ThrowArgumentNullException(ExceptionArgument argument) {
80             throw new ArgumentNullException(GetArgumentName(argument));
81         }
82
83         internal static void ThrowArgumentOutOfRangeException(ExceptionArgument argument) {
84             throw new ArgumentOutOfRangeException(GetArgumentName(argument));
85         }
86
87         internal static void ThrowArgumentOutOfRangeException(ExceptionArgument argument, ExceptionResource resource) {
88                 
89             if (CompatibilitySwitches.IsAppEarlierThanWindowsPhone8) {
90                 // Dev11 474369 quirk: Mango had an empty message string:
91                 throw new ArgumentOutOfRangeException(GetArgumentName(argument), String.Empty);                                                  
92             } else {
93                 throw new ArgumentOutOfRangeException(GetArgumentName(argument),
94                                                       Environment.GetResourceString(GetResourceName(resource)));
95             }            
96         }
97
98         internal static void ThrowInvalidOperationException(ExceptionResource resource) {
99             throw new InvalidOperationException(Environment.GetResourceString(GetResourceName(resource)));
100         }
101
102         internal static void ThrowSerializationException(ExceptionResource resource) {
103             throw new SerializationException(Environment.GetResourceString(GetResourceName(resource)));
104         }
105
106         internal static void  ThrowSecurityException(ExceptionResource resource) {
107             throw new System.Security.SecurityException(Environment.GetResourceString(GetResourceName(resource)));            
108         }
109
110         internal static void ThrowNotSupportedException(ExceptionResource resource) {
111             throw new NotSupportedException(Environment.GetResourceString(GetResourceName(resource)));
112         }
113
114         internal static void ThrowUnauthorizedAccessException(ExceptionResource resource) {
115             throw new UnauthorizedAccessException(Environment.GetResourceString(GetResourceName(resource)));
116         }
117
118         internal static void ThrowObjectDisposedException(string objectName, ExceptionResource resource) {
119             throw new ObjectDisposedException(objectName, Environment.GetResourceString(GetResourceName(resource)));
120         }
121
122         // Allow nulls for reference types and Nullable<U>, but not for value types.
123         internal static void IfNullAndNullsAreIllegalThenThrow<T>(object value, ExceptionArgument argName) {
124             // Note that default(T) is not equal to null for value types except when T is Nullable<U>. 
125             if (value == null && !(default(T) == null))
126                 ThrowHelper.ThrowArgumentNullException(argName);
127         }
128
129         //
130         // This function will convert an ExceptionArgument enum value to the argument name string.
131         //
132         internal static string GetArgumentName(ExceptionArgument argument) {
133             string argumentName = null;
134
135             switch (argument) {
136                 case ExceptionArgument.array:
137                     argumentName = "array";
138                     break;
139
140                 case ExceptionArgument.arrayIndex:
141                     argumentName = "arrayIndex";
142                     break;
143
144                 case ExceptionArgument.capacity:
145                     argumentName = "capacity";
146                     break;
147
148                 case ExceptionArgument.collection:
149                     argumentName = "collection";
150                     break;
151
152                 case ExceptionArgument.list:
153                     argumentName = "list";
154                     break;
155
156                 case ExceptionArgument.converter:
157                     argumentName = "converter";
158                     break;
159
160                 case ExceptionArgument.count:
161                     argumentName = "count";
162                     break;
163
164                 case ExceptionArgument.dictionary:
165                     argumentName = "dictionary";
166                     break;
167
168                 case ExceptionArgument.dictionaryCreationThreshold:
169                     argumentName = "dictionaryCreationThreshold";
170                     break;
171
172                 case ExceptionArgument.index:
173                     argumentName = "index";
174                     break;
175
176                 case ExceptionArgument.info:
177                     argumentName = "info";
178                     break;
179
180                 case ExceptionArgument.key:
181                     argumentName = "key";
182                     break;
183
184                 case ExceptionArgument.match:
185                     argumentName = "match";
186                     break;
187
188                 case ExceptionArgument.obj:
189                     argumentName = "obj";
190                     break;
191
192                 case ExceptionArgument.queue:
193                     argumentName = "queue";
194                     break;
195
196                 case ExceptionArgument.stack:
197                     argumentName = "stack";
198                     break;
199
200                 case ExceptionArgument.startIndex:
201                     argumentName = "startIndex";
202                     break;
203
204                 case ExceptionArgument.value:
205                     argumentName = "value";
206                     break;
207
208                 case ExceptionArgument.name:
209                     argumentName = "name";
210                     break;
211
212                 case ExceptionArgument.mode:
213                     argumentName = "mode";
214                     break;
215
216                 case ExceptionArgument.item:
217                     argumentName = "item";
218                     break;
219
220                 case ExceptionArgument.options:
221                     argumentName = "options";
222                     break;
223
224                 case ExceptionArgument.view:
225                     argumentName = "view";
226                     break;
227
228                case ExceptionArgument.sourceBytesToCopy:
229                     argumentName = "sourceBytesToCopy";
230                     break;
231
232                 default:
233                     Contract.Assert(false, "The enum value is not defined, please checked ExceptionArgumentName Enum.");
234                     return string.Empty;
235             }
236
237             return argumentName;
238         }
239
240         //
241         // This function will convert an ExceptionResource enum value to the resource string.
242         //
243         internal static string GetResourceName(ExceptionResource resource) {
244             string resourceName = null;
245
246             switch (resource) {
247                 case ExceptionResource.Argument_ImplementIComparable:
248                     resourceName = "Argument_ImplementIComparable";
249                     break;
250
251                 case ExceptionResource.Argument_AddingDuplicate:
252                     resourceName = "Argument_AddingDuplicate";
253                     break;
254
255                 case ExceptionResource.ArgumentOutOfRange_BiggerThanCollection:
256                     resourceName = "ArgumentOutOfRange_BiggerThanCollection";
257                     break;
258
259                 case ExceptionResource.ArgumentOutOfRange_Count:
260                     resourceName = "ArgumentOutOfRange_Count";
261                     break;
262
263                 case ExceptionResource.ArgumentOutOfRange_Index:
264                     resourceName = "ArgumentOutOfRange_Index";
265                     break;
266
267                 case ExceptionResource.ArgumentOutOfRange_InvalidThreshold:
268                     resourceName = "ArgumentOutOfRange_InvalidThreshold";
269                     break;
270
271                 case ExceptionResource.ArgumentOutOfRange_ListInsert:
272                     resourceName = "ArgumentOutOfRange_ListInsert";
273                     break;
274
275                 case ExceptionResource.ArgumentOutOfRange_NeedNonNegNum:
276                     resourceName = "ArgumentOutOfRange_NeedNonNegNum";
277                     break;
278
279                 case ExceptionResource.ArgumentOutOfRange_SmallCapacity:
280                     resourceName = "ArgumentOutOfRange_SmallCapacity";
281                     break;
282
283                 case ExceptionResource.Arg_ArrayPlusOffTooSmall:
284                     resourceName = "Arg_ArrayPlusOffTooSmall";
285                     break;
286
287                 case ExceptionResource.Arg_RankMultiDimNotSupported:
288                     resourceName = "Arg_RankMultiDimNotSupported";
289                     break;
290
291                 case ExceptionResource.Arg_NonZeroLowerBound:
292                     resourceName = "Arg_NonZeroLowerBound";
293                     break;
294
295                 case ExceptionResource.Argument_InvalidArrayType:
296                     resourceName = "Argument_InvalidArrayType";
297                     break;
298
299                 case ExceptionResource.Argument_InvalidOffLen:
300                     resourceName = "Argument_InvalidOffLen";
301                     break;
302
303                 case ExceptionResource.Argument_ItemNotExist:
304                     resourceName = "Argument_ItemNotExist";
305                     break;                    
306
307                 case ExceptionResource.InvalidOperation_CannotRemoveFromStackOrQueue:
308                     resourceName = "InvalidOperation_CannotRemoveFromStackOrQueue";
309                     break;
310
311                 case ExceptionResource.InvalidOperation_EmptyQueue:
312                     resourceName = "InvalidOperation_EmptyQueue";
313                     break;
314
315                 case ExceptionResource.InvalidOperation_EnumOpCantHappen:
316                     resourceName = "InvalidOperation_EnumOpCantHappen";
317                     break;
318
319                 case ExceptionResource.InvalidOperation_EnumFailedVersion:
320                     resourceName = "InvalidOperation_EnumFailedVersion";
321                     break;
322
323                 case ExceptionResource.InvalidOperation_EmptyStack:
324                     resourceName = "InvalidOperation_EmptyStack";
325                     break;
326
327                 case ExceptionResource.InvalidOperation_EnumNotStarted:
328                     resourceName = "InvalidOperation_EnumNotStarted";
329                     break;
330
331                 case ExceptionResource.InvalidOperation_EnumEnded:
332                     resourceName = "InvalidOperation_EnumEnded";
333                     break;
334
335                 case ExceptionResource.NotSupported_KeyCollectionSet:
336                     resourceName = "NotSupported_KeyCollectionSet";
337                     break;
338
339                 case ExceptionResource.NotSupported_ReadOnlyCollection:
340                     resourceName = "NotSupported_ReadOnlyCollection";
341                     break;
342
343                 case ExceptionResource.NotSupported_ValueCollectionSet:
344                     resourceName = "NotSupported_ValueCollectionSet";
345                     break;
346
347
348                 case ExceptionResource.NotSupported_SortedListNestedWrite:
349                     resourceName = "NotSupported_SortedListNestedWrite";
350                     break;
351
352
353                 case ExceptionResource.Serialization_InvalidOnDeser:
354                     resourceName = "Serialization_InvalidOnDeser";
355                     break;
356
357                 case ExceptionResource.Serialization_MissingKeys:
358                     resourceName = "Serialization_MissingKeys";
359                     break;
360
361                 case ExceptionResource.Serialization_NullKey:
362                     resourceName = "Serialization_NullKey";
363                     break;
364
365                 case ExceptionResource.Argument_InvalidType:
366                     resourceName = "Argument_InvalidType";
367                     break;
368
369                 case ExceptionResource.Argument_InvalidArgumentForComparison:
370                     resourceName = "Argument_InvalidArgumentForComparison";                    
371                     break;
372
373                 case ExceptionResource.InvalidOperation_NoValue:
374                     resourceName = "InvalidOperation_NoValue";                    
375                     break;
376
377                 case ExceptionResource.InvalidOperation_RegRemoveSubKey:
378                     resourceName = "InvalidOperation_RegRemoveSubKey";                    
379                     break;
380
381                 case ExceptionResource.Arg_RegSubKeyAbsent:
382                     resourceName = "Arg_RegSubKeyAbsent";                    
383                     break;
384
385                 case ExceptionResource.Arg_RegSubKeyValueAbsent:
386                     resourceName = "Arg_RegSubKeyValueAbsent";                    
387                     break;
388                     
389                 case ExceptionResource.Arg_RegKeyDelHive:
390                     resourceName = "Arg_RegKeyDelHive";                    
391                     break;
392
393                 case ExceptionResource.Security_RegistryPermission:
394                     resourceName = "Security_RegistryPermission";                    
395                     break;
396
397                 case ExceptionResource.Arg_RegSetStrArrNull:
398                     resourceName = "Arg_RegSetStrArrNull";                    
399                     break;
400
401                 case ExceptionResource.Arg_RegSetMismatchedKind:
402                     resourceName = "Arg_RegSetMismatchedKind";                    
403                     break;
404
405                 case ExceptionResource.UnauthorizedAccess_RegistryNoWrite:
406                     resourceName = "UnauthorizedAccess_RegistryNoWrite";
407                     break;
408
409                 case ExceptionResource.ObjectDisposed_RegKeyClosed:
410                     resourceName = "ObjectDisposed_RegKeyClosed";
411                     break;
412
413                 case ExceptionResource.Arg_RegKeyStrLenBug:
414                     resourceName = "Arg_RegKeyStrLenBug";
415                     break;
416
417                 case ExceptionResource.Argument_InvalidRegistryKeyPermissionCheck:
418                     resourceName = "Argument_InvalidRegistryKeyPermissionCheck";
419                     break;
420
421                 case ExceptionResource.NotSupported_InComparableType:
422                     resourceName = "NotSupported_InComparableType";
423                     break;
424
425                 case ExceptionResource.Argument_InvalidRegistryOptionsCheck:
426                     resourceName = "Argument_InvalidRegistryOptionsCheck";
427                     break;
428
429                 case ExceptionResource.Argument_InvalidRegistryViewCheck:
430                     resourceName = "Argument_InvalidRegistryViewCheck";
431                     break;
432
433                 default:
434                     Contract.Assert( false, "The enum value is not defined, please checked ExceptionArgumentName Enum.");
435                     return string.Empty;
436             }
437
438             return resourceName;
439         }
440
441     }
442
443     //
444     // The convention for this enum is using the argument name as the enum name
445     // 
446     internal enum ExceptionArgument {
447         obj,
448         dictionary,
449         dictionaryCreationThreshold,
450         array,
451         info,
452         key,
453         collection,
454         list,
455         match,
456         converter,
457         queue,
458         stack,
459         capacity,
460         index,
461         startIndex,
462         value,
463         count,
464         arrayIndex,
465         name,
466         mode,
467         item,
468         options,
469         view,
470         sourceBytesToCopy,
471     }
472
473     //
474     // The convention for this enum is using the resource name as the enum name
475     // 
476     internal enum ExceptionResource {
477         Argument_ImplementIComparable,
478         Argument_InvalidType,     
479         Argument_InvalidArgumentForComparison,
480         Argument_InvalidRegistryKeyPermissionCheck,        
481         ArgumentOutOfRange_NeedNonNegNum,
482         
483         Arg_ArrayPlusOffTooSmall,
484         Arg_NonZeroLowerBound,        
485         Arg_RankMultiDimNotSupported,        
486         Arg_RegKeyDelHive,
487         Arg_RegKeyStrLenBug,  
488         Arg_RegSetStrArrNull,
489         Arg_RegSetMismatchedKind,
490         Arg_RegSubKeyAbsent,        
491         Arg_RegSubKeyValueAbsent,
492         
493         Argument_AddingDuplicate,
494         Serialization_InvalidOnDeser,
495         Serialization_MissingKeys,
496         Serialization_NullKey,
497         Argument_InvalidArrayType,
498         NotSupported_KeyCollectionSet,
499         NotSupported_ValueCollectionSet,
500         ArgumentOutOfRange_SmallCapacity,
501         ArgumentOutOfRange_Index,
502         Argument_InvalidOffLen,
503         Argument_ItemNotExist,
504         ArgumentOutOfRange_Count,
505         ArgumentOutOfRange_InvalidThreshold,
506         ArgumentOutOfRange_ListInsert,
507         NotSupported_ReadOnlyCollection,
508         InvalidOperation_CannotRemoveFromStackOrQueue,
509         InvalidOperation_EmptyQueue,
510         InvalidOperation_EnumOpCantHappen,
511         InvalidOperation_EnumFailedVersion,
512         InvalidOperation_EmptyStack,
513         ArgumentOutOfRange_BiggerThanCollection,
514         InvalidOperation_EnumNotStarted,
515         InvalidOperation_EnumEnded,
516         NotSupported_SortedListNestedWrite,
517         InvalidOperation_NoValue,
518         InvalidOperation_RegRemoveSubKey,
519         Security_RegistryPermission,
520         UnauthorizedAccess_RegistryNoWrite,
521         ObjectDisposed_RegKeyClosed,
522         NotSupported_InComparableType,
523         Argument_InvalidRegistryOptionsCheck,
524         Argument_InvalidRegistryViewCheck
525     }
526 }
527