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 partial 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));
80 internal static void ThrowArgumentNullException(ExceptionArgument argument) {
81 throw new ArgumentNullException(GetArgumentName(argument));
84 internal static void ThrowArgumentOutOfRangeException(ExceptionArgument argument) {
85 throw new ArgumentOutOfRangeException(GetArgumentName(argument));
89 internal static void ThrowArgumentOutOfRangeException(ExceptionArgument argument, ExceptionResource resource) {
91 if (CompatibilitySwitches.IsAppEarlierThanWindowsPhone8) {
92 // Dev11 474369 quirk: Mango had an empty message string:
93 throw new ArgumentOutOfRangeException(GetArgumentName(argument), String.Empty);
95 throw new ArgumentOutOfRangeException(GetArgumentName(argument),
96 Environment.GetResourceString(GetResourceName(resource)));
100 internal static void ThrowInvalidOperationException(ExceptionResource resource) {
101 throw new InvalidOperationException(Environment.GetResourceString(GetResourceName(resource)));
104 internal static void ThrowSerializationException(ExceptionResource resource) {
105 throw new SerializationException(Environment.GetResourceString(GetResourceName(resource)));
108 internal static void ThrowSecurityException(ExceptionResource resource) {
109 throw new System.Security.SecurityException(Environment.GetResourceString(GetResourceName(resource)));
112 internal static void ThrowNotSupportedException(ExceptionResource resource) {
113 throw new NotSupportedException(Environment.GetResourceString(GetResourceName(resource)));
116 internal static void ThrowUnauthorizedAccessException(ExceptionResource resource) {
117 throw new UnauthorizedAccessException(Environment.GetResourceString(GetResourceName(resource)));
120 internal static void ThrowObjectDisposedException(string objectName, ExceptionResource resource) {
121 throw new ObjectDisposedException(objectName, Environment.GetResourceString(GetResourceName(resource)));
124 // Allow nulls for reference types and Nullable<U>, but not for value types.
125 internal static void IfNullAndNullsAreIllegalThenThrow<T>(object value, ExceptionArgument argName) {
126 // Note that default(T) is not equal to null for value types except when T is Nullable<U>.
127 if (value == null && !(default(T) == null))
128 ThrowHelper.ThrowArgumentNullException(argName);
132 // This function will convert an ExceptionArgument enum value to the argument name string.
134 internal static string GetArgumentName(ExceptionArgument argument) {
135 string argumentName = null;
138 case ExceptionArgument.array:
139 argumentName = "array";
142 case ExceptionArgument.arrayIndex:
143 argumentName = "arrayIndex";
146 case ExceptionArgument.capacity:
147 argumentName = "capacity";
150 case ExceptionArgument.collection:
151 argumentName = "collection";
154 case ExceptionArgument.list:
155 argumentName = "list";
158 case ExceptionArgument.converter:
159 argumentName = "converter";
162 case ExceptionArgument.count:
163 argumentName = "count";
166 case ExceptionArgument.dictionary:
167 argumentName = "dictionary";
170 case ExceptionArgument.dictionaryCreationThreshold:
171 argumentName = "dictionaryCreationThreshold";
174 case ExceptionArgument.index:
175 argumentName = "index";
178 case ExceptionArgument.info:
179 argumentName = "info";
182 case ExceptionArgument.key:
183 argumentName = "key";
186 case ExceptionArgument.match:
187 argumentName = "match";
190 case ExceptionArgument.obj:
191 argumentName = "obj";
194 case ExceptionArgument.queue:
195 argumentName = "queue";
198 case ExceptionArgument.stack:
199 argumentName = "stack";
202 case ExceptionArgument.startIndex:
203 argumentName = "startIndex";
206 case ExceptionArgument.value:
207 argumentName = "value";
210 case ExceptionArgument.name:
211 argumentName = "name";
214 case ExceptionArgument.mode:
215 argumentName = "mode";
218 case ExceptionArgument.item:
219 argumentName = "item";
222 case ExceptionArgument.options:
223 argumentName = "options";
226 case ExceptionArgument.view:
227 argumentName = "view";
230 case ExceptionArgument.sourceBytesToCopy:
231 argumentName = "sourceBytesToCopy";
235 Contract.Assert(false, "The enum value is not defined, please checked ExceptionArgumentName Enum.");
243 // This function will convert an ExceptionResource enum value to the resource string.
245 internal static string GetResourceName(ExceptionResource resource) {
246 string resourceName = null;
249 case ExceptionResource.Argument_ImplementIComparable:
250 resourceName = "Argument_ImplementIComparable";
253 case ExceptionResource.Argument_AddingDuplicate:
254 resourceName = "Argument_AddingDuplicate";
257 case ExceptionResource.ArgumentOutOfRange_BiggerThanCollection:
258 resourceName = "ArgumentOutOfRange_BiggerThanCollection";
261 case ExceptionResource.ArgumentOutOfRange_Count:
262 resourceName = "ArgumentOutOfRange_Count";
265 case ExceptionResource.ArgumentOutOfRange_Index:
266 resourceName = "ArgumentOutOfRange_Index";
269 case ExceptionResource.ArgumentOutOfRange_InvalidThreshold:
270 resourceName = "ArgumentOutOfRange_InvalidThreshold";
273 case ExceptionResource.ArgumentOutOfRange_ListInsert:
274 resourceName = "ArgumentOutOfRange_ListInsert";
277 case ExceptionResource.ArgumentOutOfRange_NeedNonNegNum:
278 resourceName = "ArgumentOutOfRange_NeedNonNegNum";
281 case ExceptionResource.ArgumentOutOfRange_SmallCapacity:
282 resourceName = "ArgumentOutOfRange_SmallCapacity";
285 case ExceptionResource.Arg_ArrayPlusOffTooSmall:
286 resourceName = "Arg_ArrayPlusOffTooSmall";
289 case ExceptionResource.Arg_RankMultiDimNotSupported:
290 resourceName = "Arg_RankMultiDimNotSupported";
293 case ExceptionResource.Arg_NonZeroLowerBound:
294 resourceName = "Arg_NonZeroLowerBound";
297 case ExceptionResource.Argument_InvalidArrayType:
298 resourceName = "Argument_InvalidArrayType";
301 case ExceptionResource.Argument_InvalidOffLen:
302 resourceName = "Argument_InvalidOffLen";
305 case ExceptionResource.Argument_ItemNotExist:
306 resourceName = "Argument_ItemNotExist";
309 case ExceptionResource.InvalidOperation_CannotRemoveFromStackOrQueue:
310 resourceName = "InvalidOperation_CannotRemoveFromStackOrQueue";
313 case ExceptionResource.InvalidOperation_EmptyQueue:
314 resourceName = "InvalidOperation_EmptyQueue";
317 case ExceptionResource.InvalidOperation_EnumOpCantHappen:
318 resourceName = "InvalidOperation_EnumOpCantHappen";
321 case ExceptionResource.InvalidOperation_EnumFailedVersion:
322 resourceName = "InvalidOperation_EnumFailedVersion";
325 case ExceptionResource.InvalidOperation_EmptyStack:
326 resourceName = "InvalidOperation_EmptyStack";
329 case ExceptionResource.InvalidOperation_EnumNotStarted:
330 resourceName = "InvalidOperation_EnumNotStarted";
333 case ExceptionResource.InvalidOperation_EnumEnded:
334 resourceName = "InvalidOperation_EnumEnded";
337 case ExceptionResource.NotSupported_KeyCollectionSet:
338 resourceName = "NotSupported_KeyCollectionSet";
341 case ExceptionResource.NotSupported_ReadOnlyCollection:
342 resourceName = "NotSupported_ReadOnlyCollection";
345 case ExceptionResource.NotSupported_ValueCollectionSet:
346 resourceName = "NotSupported_ValueCollectionSet";
350 case ExceptionResource.NotSupported_SortedListNestedWrite:
351 resourceName = "NotSupported_SortedListNestedWrite";
355 case ExceptionResource.Serialization_InvalidOnDeser:
356 resourceName = "Serialization_InvalidOnDeser";
359 case ExceptionResource.Serialization_MissingKeys:
360 resourceName = "Serialization_MissingKeys";
363 case ExceptionResource.Serialization_NullKey:
364 resourceName = "Serialization_NullKey";
367 case ExceptionResource.Argument_InvalidType:
368 resourceName = "Argument_InvalidType";
371 case ExceptionResource.Argument_InvalidArgumentForComparison:
372 resourceName = "Argument_InvalidArgumentForComparison";
375 case ExceptionResource.InvalidOperation_NoValue:
376 resourceName = "InvalidOperation_NoValue";
379 case ExceptionResource.InvalidOperation_RegRemoveSubKey:
380 resourceName = "InvalidOperation_RegRemoveSubKey";
383 case ExceptionResource.Arg_RegSubKeyAbsent:
384 resourceName = "Arg_RegSubKeyAbsent";
387 case ExceptionResource.Arg_RegSubKeyValueAbsent:
388 resourceName = "Arg_RegSubKeyValueAbsent";
391 case ExceptionResource.Arg_RegKeyDelHive:
392 resourceName = "Arg_RegKeyDelHive";
395 case ExceptionResource.Security_RegistryPermission:
396 resourceName = "Security_RegistryPermission";
399 case ExceptionResource.Arg_RegSetStrArrNull:
400 resourceName = "Arg_RegSetStrArrNull";
403 case ExceptionResource.Arg_RegSetMismatchedKind:
404 resourceName = "Arg_RegSetMismatchedKind";
407 case ExceptionResource.UnauthorizedAccess_RegistryNoWrite:
408 resourceName = "UnauthorizedAccess_RegistryNoWrite";
411 case ExceptionResource.ObjectDisposed_RegKeyClosed:
412 resourceName = "ObjectDisposed_RegKeyClosed";
415 case ExceptionResource.Arg_RegKeyStrLenBug:
416 resourceName = "Arg_RegKeyStrLenBug";
419 case ExceptionResource.Argument_InvalidRegistryKeyPermissionCheck:
420 resourceName = "Argument_InvalidRegistryKeyPermissionCheck";
423 case ExceptionResource.NotSupported_InComparableType:
424 resourceName = "NotSupported_InComparableType";
427 case ExceptionResource.Argument_InvalidRegistryOptionsCheck:
428 resourceName = "Argument_InvalidRegistryOptionsCheck";
431 case ExceptionResource.Argument_InvalidRegistryViewCheck:
432 resourceName = "Argument_InvalidRegistryViewCheck";
436 Contract.Assert( false, "The enum value is not defined, please checked ExceptionArgumentName Enum.");
446 // The convention for this enum is using the argument name as the enum name
448 internal enum ExceptionArgument {
451 dictionaryCreationThreshold,
479 // The convention for this enum is using the resource name as the enum name
481 internal enum ExceptionResource {
482 Argument_ImplementIComparable,
483 Argument_InvalidType,
484 Argument_InvalidArgumentForComparison,
485 Argument_InvalidRegistryKeyPermissionCheck,
486 ArgumentOutOfRange_NeedNonNegNum,
488 Arg_ArrayPlusOffTooSmall,
489 Arg_NonZeroLowerBound,
490 Arg_RankMultiDimNotSupported,
493 Arg_RegSetStrArrNull,
494 Arg_RegSetMismatchedKind,
496 Arg_RegSubKeyValueAbsent,
498 Argument_AddingDuplicate,
499 Serialization_InvalidOnDeser,
500 Serialization_MissingKeys,
501 Serialization_NullKey,
502 Argument_InvalidArrayType,
503 NotSupported_KeyCollectionSet,
504 NotSupported_ValueCollectionSet,
505 ArgumentOutOfRange_SmallCapacity,
506 ArgumentOutOfRange_Index,
507 Argument_InvalidOffLen,
508 Argument_ItemNotExist,
509 ArgumentOutOfRange_Count,
510 ArgumentOutOfRange_InvalidThreshold,
511 ArgumentOutOfRange_ListInsert,
512 NotSupported_ReadOnlyCollection,
513 InvalidOperation_CannotRemoveFromStackOrQueue,
514 InvalidOperation_EmptyQueue,
515 InvalidOperation_EnumOpCantHappen,
516 InvalidOperation_EnumFailedVersion,
517 InvalidOperation_EmptyStack,
518 ArgumentOutOfRange_BiggerThanCollection,
519 InvalidOperation_EnumNotStarted,
520 InvalidOperation_EnumEnded,
521 NotSupported_SortedListNestedWrite,
522 InvalidOperation_NoValue,
523 InvalidOperation_RegRemoveSubKey,
524 Security_RegistryPermission,
525 UnauthorizedAccess_RegistryNoWrite,
526 ObjectDisposed_RegKeyClosed,
527 NotSupported_InComparableType,
528 Argument_InvalidRegistryOptionsCheck,
529 Argument_InvalidRegistryViewCheck