3 // Copyright (c) Microsoft Corporation. All rights reserved.
8 // This file defines an internal class used to throw exceptions in BCL code.
9 // The main purpose is to reduce code size.
11 // The old way to throw an exception generates quite a lot IL code and assembly code.
12 // Following is an example:
14 // throw new ArgumentNullException("key", Environment.GetResourceString("ArgumentNull_Key"));
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)
21 // which is 21bytes in IL.
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);
28 // The IL code will be 7 bytes.
31 // IL_000a: call void System.ThrowHelper::ThrowArgumentNullException(valuetype System.ExceptionArgument)
34 // This will also reduce the Jitted code size a lot.
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.
49 using System.Runtime.CompilerServices;
50 using System.Runtime.Serialization;
51 using System.Diagnostics.Contracts;
54 internal static class ThrowHelper {
55 internal static void ThrowArgumentOutOfRangeException() {
56 ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_Index);
59 internal static void ThrowWrongKeyTypeArgumentException(object key, Type targetType) {
60 throw new ArgumentException(Environment.GetResourceString("Arg_WrongType", key, targetType), "key");
63 internal static void ThrowWrongValueTypeArgumentException(object value, Type targetType) {
64 throw new ArgumentException(Environment.GetResourceString("Arg_WrongType", value, targetType), "value");
67 internal static void ThrowKeyNotFoundException() {
68 throw new System.Collections.Generic.KeyNotFoundException();
71 internal static void ThrowArgumentException(ExceptionResource resource) {
72 throw new ArgumentException(Environment.GetResourceString(GetResourceName(resource)));
75 internal static void ThrowArgumentException(ExceptionResource resource, ExceptionArgument argument) {
76 throw new ArgumentException(Environment.GetResourceString(GetResourceName(resource)), GetArgumentName(argument));
79 internal static void ThrowArgumentNullException(ExceptionArgument argument) {
80 throw new ArgumentNullException(GetArgumentName(argument));
83 internal static void ThrowArgumentOutOfRangeException(ExceptionArgument argument) {
84 throw new ArgumentOutOfRangeException(GetArgumentName(argument));
87 internal static void ThrowArgumentOutOfRangeException(ExceptionArgument argument, ExceptionResource resource) {
89 if (CompatibilitySwitches.IsAppEarlierThanWindowsPhone8) {
90 // Dev11 474369 quirk: Mango had an empty message string:
91 throw new ArgumentOutOfRangeException(GetArgumentName(argument), String.Empty);
93 throw new ArgumentOutOfRangeException(GetArgumentName(argument),
94 Environment.GetResourceString(GetResourceName(resource)));
98 internal static void ThrowInvalidOperationException(ExceptionResource resource) {
99 throw new InvalidOperationException(Environment.GetResourceString(GetResourceName(resource)));
102 internal static void ThrowSerializationException(ExceptionResource resource) {
103 throw new SerializationException(Environment.GetResourceString(GetResourceName(resource)));
106 internal static void ThrowSecurityException(ExceptionResource resource) {
107 throw new System.Security.SecurityException(Environment.GetResourceString(GetResourceName(resource)));
110 internal static void ThrowNotSupportedException(ExceptionResource resource) {
111 throw new NotSupportedException(Environment.GetResourceString(GetResourceName(resource)));
114 internal static void ThrowUnauthorizedAccessException(ExceptionResource resource) {
115 throw new UnauthorizedAccessException(Environment.GetResourceString(GetResourceName(resource)));
118 internal static void ThrowObjectDisposedException(string objectName, ExceptionResource resource) {
119 throw new ObjectDisposedException(objectName, Environment.GetResourceString(GetResourceName(resource)));
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);
130 // This function will convert an ExceptionArgument enum value to the argument name string.
132 internal static string GetArgumentName(ExceptionArgument argument) {
133 string argumentName = null;
136 case ExceptionArgument.array:
137 argumentName = "array";
140 case ExceptionArgument.arrayIndex:
141 argumentName = "arrayIndex";
144 case ExceptionArgument.capacity:
145 argumentName = "capacity";
148 case ExceptionArgument.collection:
149 argumentName = "collection";
152 case ExceptionArgument.list:
153 argumentName = "list";
156 case ExceptionArgument.converter:
157 argumentName = "converter";
160 case ExceptionArgument.count:
161 argumentName = "count";
164 case ExceptionArgument.dictionary:
165 argumentName = "dictionary";
168 case ExceptionArgument.dictionaryCreationThreshold:
169 argumentName = "dictionaryCreationThreshold";
172 case ExceptionArgument.index:
173 argumentName = "index";
176 case ExceptionArgument.info:
177 argumentName = "info";
180 case ExceptionArgument.key:
181 argumentName = "key";
184 case ExceptionArgument.match:
185 argumentName = "match";
188 case ExceptionArgument.obj:
189 argumentName = "obj";
192 case ExceptionArgument.queue:
193 argumentName = "queue";
196 case ExceptionArgument.stack:
197 argumentName = "stack";
200 case ExceptionArgument.startIndex:
201 argumentName = "startIndex";
204 case ExceptionArgument.value:
205 argumentName = "value";
208 case ExceptionArgument.name:
209 argumentName = "name";
212 case ExceptionArgument.mode:
213 argumentName = "mode";
216 case ExceptionArgument.item:
217 argumentName = "item";
220 case ExceptionArgument.options:
221 argumentName = "options";
224 case ExceptionArgument.view:
225 argumentName = "view";
228 case ExceptionArgument.sourceBytesToCopy:
229 argumentName = "sourceBytesToCopy";
233 Contract.Assert(false, "The enum value is not defined, please checked ExceptionArgumentName Enum.");
241 // This function will convert an ExceptionResource enum value to the resource string.
243 internal static string GetResourceName(ExceptionResource resource) {
244 string resourceName = null;
247 case ExceptionResource.Argument_ImplementIComparable:
248 resourceName = "Argument_ImplementIComparable";
251 case ExceptionResource.Argument_AddingDuplicate:
252 resourceName = "Argument_AddingDuplicate";
255 case ExceptionResource.ArgumentOutOfRange_BiggerThanCollection:
256 resourceName = "ArgumentOutOfRange_BiggerThanCollection";
259 case ExceptionResource.ArgumentOutOfRange_Count:
260 resourceName = "ArgumentOutOfRange_Count";
263 case ExceptionResource.ArgumentOutOfRange_Index:
264 resourceName = "ArgumentOutOfRange_Index";
267 case ExceptionResource.ArgumentOutOfRange_InvalidThreshold:
268 resourceName = "ArgumentOutOfRange_InvalidThreshold";
271 case ExceptionResource.ArgumentOutOfRange_ListInsert:
272 resourceName = "ArgumentOutOfRange_ListInsert";
275 case ExceptionResource.ArgumentOutOfRange_NeedNonNegNum:
276 resourceName = "ArgumentOutOfRange_NeedNonNegNum";
279 case ExceptionResource.ArgumentOutOfRange_SmallCapacity:
280 resourceName = "ArgumentOutOfRange_SmallCapacity";
283 case ExceptionResource.Arg_ArrayPlusOffTooSmall:
284 resourceName = "Arg_ArrayPlusOffTooSmall";
287 case ExceptionResource.Arg_RankMultiDimNotSupported:
288 resourceName = "Arg_RankMultiDimNotSupported";
291 case ExceptionResource.Arg_NonZeroLowerBound:
292 resourceName = "Arg_NonZeroLowerBound";
295 case ExceptionResource.Argument_InvalidArrayType:
296 resourceName = "Argument_InvalidArrayType";
299 case ExceptionResource.Argument_InvalidOffLen:
300 resourceName = "Argument_InvalidOffLen";
303 case ExceptionResource.Argument_ItemNotExist:
304 resourceName = "Argument_ItemNotExist";
307 case ExceptionResource.InvalidOperation_CannotRemoveFromStackOrQueue:
308 resourceName = "InvalidOperation_CannotRemoveFromStackOrQueue";
311 case ExceptionResource.InvalidOperation_EmptyQueue:
312 resourceName = "InvalidOperation_EmptyQueue";
315 case ExceptionResource.InvalidOperation_EnumOpCantHappen:
316 resourceName = "InvalidOperation_EnumOpCantHappen";
319 case ExceptionResource.InvalidOperation_EnumFailedVersion:
320 resourceName = "InvalidOperation_EnumFailedVersion";
323 case ExceptionResource.InvalidOperation_EmptyStack:
324 resourceName = "InvalidOperation_EmptyStack";
327 case ExceptionResource.InvalidOperation_EnumNotStarted:
328 resourceName = "InvalidOperation_EnumNotStarted";
331 case ExceptionResource.InvalidOperation_EnumEnded:
332 resourceName = "InvalidOperation_EnumEnded";
335 case ExceptionResource.NotSupported_KeyCollectionSet:
336 resourceName = "NotSupported_KeyCollectionSet";
339 case ExceptionResource.NotSupported_ReadOnlyCollection:
340 resourceName = "NotSupported_ReadOnlyCollection";
343 case ExceptionResource.NotSupported_ValueCollectionSet:
344 resourceName = "NotSupported_ValueCollectionSet";
348 case ExceptionResource.NotSupported_SortedListNestedWrite:
349 resourceName = "NotSupported_SortedListNestedWrite";
353 case ExceptionResource.Serialization_InvalidOnDeser:
354 resourceName = "Serialization_InvalidOnDeser";
357 case ExceptionResource.Serialization_MissingKeys:
358 resourceName = "Serialization_MissingKeys";
361 case ExceptionResource.Serialization_NullKey:
362 resourceName = "Serialization_NullKey";
365 case ExceptionResource.Argument_InvalidType:
366 resourceName = "Argument_InvalidType";
369 case ExceptionResource.Argument_InvalidArgumentForComparison:
370 resourceName = "Argument_InvalidArgumentForComparison";
373 case ExceptionResource.InvalidOperation_NoValue:
374 resourceName = "InvalidOperation_NoValue";
377 case ExceptionResource.InvalidOperation_RegRemoveSubKey:
378 resourceName = "InvalidOperation_RegRemoveSubKey";
381 case ExceptionResource.Arg_RegSubKeyAbsent:
382 resourceName = "Arg_RegSubKeyAbsent";
385 case ExceptionResource.Arg_RegSubKeyValueAbsent:
386 resourceName = "Arg_RegSubKeyValueAbsent";
389 case ExceptionResource.Arg_RegKeyDelHive:
390 resourceName = "Arg_RegKeyDelHive";
393 case ExceptionResource.Security_RegistryPermission:
394 resourceName = "Security_RegistryPermission";
397 case ExceptionResource.Arg_RegSetStrArrNull:
398 resourceName = "Arg_RegSetStrArrNull";
401 case ExceptionResource.Arg_RegSetMismatchedKind:
402 resourceName = "Arg_RegSetMismatchedKind";
405 case ExceptionResource.UnauthorizedAccess_RegistryNoWrite:
406 resourceName = "UnauthorizedAccess_RegistryNoWrite";
409 case ExceptionResource.ObjectDisposed_RegKeyClosed:
410 resourceName = "ObjectDisposed_RegKeyClosed";
413 case ExceptionResource.Arg_RegKeyStrLenBug:
414 resourceName = "Arg_RegKeyStrLenBug";
417 case ExceptionResource.Argument_InvalidRegistryKeyPermissionCheck:
418 resourceName = "Argument_InvalidRegistryKeyPermissionCheck";
421 case ExceptionResource.NotSupported_InComparableType:
422 resourceName = "NotSupported_InComparableType";
425 case ExceptionResource.Argument_InvalidRegistryOptionsCheck:
426 resourceName = "Argument_InvalidRegistryOptionsCheck";
429 case ExceptionResource.Argument_InvalidRegistryViewCheck:
430 resourceName = "Argument_InvalidRegistryViewCheck";
434 Contract.Assert( false, "The enum value is not defined, please checked ExceptionArgumentName Enum.");
444 // The convention for this enum is using the argument name as the enum name
446 internal enum ExceptionArgument {
449 dictionaryCreationThreshold,
474 // The convention for this enum is using the resource name as the enum name
476 internal enum ExceptionResource {
477 Argument_ImplementIComparable,
478 Argument_InvalidType,
479 Argument_InvalidArgumentForComparison,
480 Argument_InvalidRegistryKeyPermissionCheck,
481 ArgumentOutOfRange_NeedNonNegNum,
483 Arg_ArrayPlusOffTooSmall,
484 Arg_NonZeroLowerBound,
485 Arg_RankMultiDimNotSupported,
488 Arg_RegSetStrArrNull,
489 Arg_RegSetMismatchedKind,
491 Arg_RegSubKeyValueAbsent,
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