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
;
52 using System
.Collections
.Generic
;
56 [System
.Diagnostics
.StackTraceHidden
]
58 internal static partial class ThrowHelper
{
60 internal static void ThrowArgumentOutOfRangeException() {
61 ThrowArgumentOutOfRangeException(ExceptionArgument
.index
, ExceptionResource
.ArgumentOutOfRange_Index
);
65 internal static void ThrowWrongKeyTypeArgumentException(object key
, Type targetType
) {
66 throw new ArgumentException(Environment
.GetResourceString("Arg_WrongType", key
, targetType
), "key");
69 internal static void ThrowWrongValueTypeArgumentException(object value, Type targetType
) {
70 throw new ArgumentException(Environment
.GetResourceString("Arg_WrongType", value, targetType
), "value");
73 internal static void ThrowKeyNotFoundException() {
74 throw new System
.Collections
.Generic
.KeyNotFoundException();
77 internal static void ThrowArgumentException(ExceptionResource resource
) {
78 throw new ArgumentException(Environment
.GetResourceString(GetResourceName(resource
)));
81 internal static void ThrowArgumentException(ExceptionResource resource
, ExceptionArgument argument
) {
82 throw new ArgumentException(Environment
.GetResourceString(GetResourceName(resource
)), GetArgumentName(argument
));
86 internal static void ThrowArgumentNullException(ExceptionArgument argument
) {
87 throw new ArgumentNullException(GetArgumentName(argument
));
90 internal static void ThrowArgumentOutOfRangeException(ExceptionArgument argument
) {
91 throw new ArgumentOutOfRangeException(GetArgumentName(argument
));
95 internal static void ThrowArgumentOutOfRangeException(ExceptionArgument argument
, ExceptionResource resource
) {
97 if (CompatibilitySwitches
.IsAppEarlierThanWindowsPhone8
) {
98 // Dev11 474369 quirk: Mango had an empty message string:
99 throw new ArgumentOutOfRangeException(GetArgumentName(argument
), String
.Empty
);
101 throw new ArgumentOutOfRangeException(GetArgumentName(argument
),
102 Environment
.GetResourceString(GetResourceName(resource
)));
106 internal static void ThrowInvalidOperationException(ExceptionResource resource
) {
107 throw new InvalidOperationException(Environment
.GetResourceString(GetResourceName(resource
)));
110 internal static void ThrowSerializationException(ExceptionResource resource
) {
111 throw new SerializationException(Environment
.GetResourceString(GetResourceName(resource
)));
114 internal static void ThrowSecurityException(ExceptionResource resource
) {
115 throw new System
.Security
.SecurityException(Environment
.GetResourceString(GetResourceName(resource
)));
118 internal static void ThrowNotSupportedException(ExceptionResource resource
) {
119 throw new NotSupportedException(Environment
.GetResourceString(GetResourceName(resource
)));
122 internal static void ThrowUnauthorizedAccessException(ExceptionResource resource
) {
123 throw new UnauthorizedAccessException(Environment
.GetResourceString(GetResourceName(resource
)));
126 internal static void ThrowObjectDisposedException(string objectName
, ExceptionResource resource
) {
127 throw new ObjectDisposedException(objectName
, Environment
.GetResourceString(GetResourceName(resource
)));
131 internal static void ThrowInvalidOperationException_InvalidOperation_EnumFailedVersion()
133 throw new InvalidOperationException(SR
.InvalidOperation_EnumFailedVersion
);
136 internal static void ThrowInvalidOperationException_InvalidOperation_EnumOpCantHappen()
138 throw new InvalidOperationException(SR
.InvalidOperation_EnumOpCantHappen
);
141 internal static void ThrowInvalidOperationException_InvalidOperation_EnumNotStarted()
143 throw new InvalidOperationException(SR
.InvalidOperation_EnumNotStarted
);
146 internal static void ThrowInvalidOperationException_InvalidOperation_EnumEnded()
148 throw new InvalidOperationException(SR
.InvalidOperation_EnumEnded
);
151 private static ArgumentOutOfRangeException
GetArgumentOutOfRangeException(ExceptionArgument argument
, string resource
)
153 return new ArgumentOutOfRangeException(GetArgumentName(argument
), resource
);
156 internal static void ThrowArgumentOutOfRange_IndexException()
158 throw GetArgumentOutOfRangeException(ExceptionArgument
.index
,
159 SR
.ArgumentOutOfRange_Index
);
162 internal static void ThrowIndexArgumentOutOfRange_NeedNonNegNumException()
164 throw GetArgumentOutOfRangeException(ExceptionArgument
.index
,
165 SR
.ArgumentOutOfRange_NeedNonNegNum
);
168 internal static void ThrowArgumentException_Argument_InvalidArrayType()
170 throw new ArgumentException(SR
.Argument_InvalidArrayType
);
173 private static ArgumentException
GetAddingDuplicateWithKeyArgumentException(object key
)
175 return new ArgumentException(SR
.Format(SR
.Argument_AddingDuplicate
, key
));
177 internal static void ThrowAddingDuplicateWithKeyArgumentException(object key
)
179 throw GetAddingDuplicateWithKeyArgumentException(key
);
182 private static KeyNotFoundException
GetKeyNotFoundException(object key
)
184 throw new KeyNotFoundException(SR
.Format(SR
.Arg_KeyNotFoundWithKey
, key
.ToString()));
186 internal static void ThrowKeyNotFoundException(object key
)
188 throw GetKeyNotFoundException(key
);
192 // Allow nulls for reference types and Nullable<U>, but not for value types.
193 internal static void IfNullAndNullsAreIllegalThenThrow
<T
>(object value, ExceptionArgument argName
) {
194 // Note that default(T) is not equal to null for value types except when T is Nullable<U>.
195 if (value == null && !(default(T
) == null))
196 ThrowHelper
.ThrowArgumentNullException(argName
);
200 // This function will convert an ExceptionArgument enum value to the argument name string.
202 internal static string GetArgumentName(ExceptionArgument argument
) {
203 string argumentName
= null;
206 case ExceptionArgument
.array
:
207 argumentName
= "array";
210 case ExceptionArgument
.arrayIndex
:
211 argumentName
= "arrayIndex";
214 case ExceptionArgument
.capacity
:
215 argumentName
= "capacity";
218 case ExceptionArgument
.collection
:
219 argumentName
= "collection";
222 case ExceptionArgument
.list
:
223 argumentName
= "list";
226 case ExceptionArgument
.converter
:
227 argumentName
= "converter";
230 case ExceptionArgument
.count
:
231 argumentName
= "count";
234 case ExceptionArgument
.dictionary
:
235 argumentName
= "dictionary";
238 case ExceptionArgument
.dictionaryCreationThreshold
:
239 argumentName
= "dictionaryCreationThreshold";
242 case ExceptionArgument
.index
:
243 argumentName
= "index";
246 case ExceptionArgument
.info
:
247 argumentName
= "info";
250 case ExceptionArgument
.key
:
251 argumentName
= "key";
254 case ExceptionArgument
.match
:
255 argumentName
= "match";
258 case ExceptionArgument
.obj
:
259 argumentName
= "obj";
262 case ExceptionArgument
.queue
:
263 argumentName
= "queue";
266 case ExceptionArgument
.stack
:
267 argumentName
= "stack";
270 case ExceptionArgument
.startIndex
:
271 argumentName
= "startIndex";
274 case ExceptionArgument
.value:
275 argumentName
= "value";
278 case ExceptionArgument
.name
:
279 argumentName
= "name";
282 case ExceptionArgument
.mode
:
283 argumentName
= "mode";
286 case ExceptionArgument
.item
:
287 argumentName
= "item";
290 case ExceptionArgument
.options
:
291 argumentName
= "options";
294 case ExceptionArgument
.view
:
295 argumentName
= "view";
298 case ExceptionArgument
.sourceBytesToCopy
:
299 argumentName
= "sourceBytesToCopy";
303 Contract
.Assert(false, "The enum value is not defined, please checked ExceptionArgumentName Enum.");
311 // This function will convert an ExceptionResource enum value to the resource string.
313 internal static string GetResourceName(ExceptionResource resource
) {
314 string resourceName
= null;
317 case ExceptionResource
.Argument_ImplementIComparable
:
318 resourceName
= "Argument_ImplementIComparable";
321 case ExceptionResource
.Argument_AddingDuplicate
:
322 resourceName
= "Argument_AddingDuplicate";
325 case ExceptionResource
.ArgumentOutOfRange_BiggerThanCollection
:
326 resourceName
= "ArgumentOutOfRange_BiggerThanCollection";
329 case ExceptionResource
.ArgumentOutOfRange_Count
:
330 resourceName
= "ArgumentOutOfRange_Count";
333 case ExceptionResource
.ArgumentOutOfRange_Index
:
334 resourceName
= "ArgumentOutOfRange_Index";
337 case ExceptionResource
.ArgumentOutOfRange_InvalidThreshold
:
338 resourceName
= "ArgumentOutOfRange_InvalidThreshold";
341 case ExceptionResource
.ArgumentOutOfRange_ListInsert
:
342 resourceName
= "ArgumentOutOfRange_ListInsert";
345 case ExceptionResource
.ArgumentOutOfRange_NeedNonNegNum
:
346 resourceName
= "ArgumentOutOfRange_NeedNonNegNum";
349 case ExceptionResource
.ArgumentOutOfRange_SmallCapacity
:
350 resourceName
= "ArgumentOutOfRange_SmallCapacity";
353 case ExceptionResource
.Arg_ArrayPlusOffTooSmall
:
354 resourceName
= "Arg_ArrayPlusOffTooSmall";
357 case ExceptionResource
.Arg_RankMultiDimNotSupported
:
358 resourceName
= "Arg_RankMultiDimNotSupported";
361 case ExceptionResource
.Arg_NonZeroLowerBound
:
362 resourceName
= "Arg_NonZeroLowerBound";
365 case ExceptionResource
.Argument_InvalidArrayType
:
366 resourceName
= "Argument_InvalidArrayType";
369 case ExceptionResource
.Argument_InvalidOffLen
:
370 resourceName
= "Argument_InvalidOffLen";
373 case ExceptionResource
.Argument_ItemNotExist
:
374 resourceName
= "Argument_ItemNotExist";
377 case ExceptionResource
.InvalidOperation_CannotRemoveFromStackOrQueue
:
378 resourceName
= "InvalidOperation_CannotRemoveFromStackOrQueue";
381 case ExceptionResource
.InvalidOperation_EmptyQueue
:
382 resourceName
= "InvalidOperation_EmptyQueue";
385 case ExceptionResource
.InvalidOperation_EnumOpCantHappen
:
386 resourceName
= "InvalidOperation_EnumOpCantHappen";
389 case ExceptionResource
.InvalidOperation_EnumFailedVersion
:
390 resourceName
= "InvalidOperation_EnumFailedVersion";
393 case ExceptionResource
.InvalidOperation_EmptyStack
:
394 resourceName
= "InvalidOperation_EmptyStack";
397 case ExceptionResource
.InvalidOperation_EnumNotStarted
:
398 resourceName
= "InvalidOperation_EnumNotStarted";
401 case ExceptionResource
.InvalidOperation_EnumEnded
:
402 resourceName
= "InvalidOperation_EnumEnded";
405 case ExceptionResource
.NotSupported_KeyCollectionSet
:
406 resourceName
= "NotSupported_KeyCollectionSet";
409 case ExceptionResource
.NotSupported_ReadOnlyCollection
:
410 resourceName
= "NotSupported_ReadOnlyCollection";
413 case ExceptionResource
.NotSupported_ValueCollectionSet
:
414 resourceName
= "NotSupported_ValueCollectionSet";
418 case ExceptionResource
.NotSupported_SortedListNestedWrite
:
419 resourceName
= "NotSupported_SortedListNestedWrite";
423 case ExceptionResource
.Serialization_InvalidOnDeser
:
424 resourceName
= "Serialization_InvalidOnDeser";
427 case ExceptionResource
.Serialization_MissingKeys
:
428 resourceName
= "Serialization_MissingKeys";
431 case ExceptionResource
.Serialization_NullKey
:
432 resourceName
= "Serialization_NullKey";
435 case ExceptionResource
.Argument_InvalidType
:
436 resourceName
= "Argument_InvalidType";
439 case ExceptionResource
.Argument_InvalidArgumentForComparison
:
440 resourceName
= "Argument_InvalidArgumentForComparison";
443 case ExceptionResource
.InvalidOperation_NoValue
:
444 resourceName
= "InvalidOperation_NoValue";
447 case ExceptionResource
.InvalidOperation_RegRemoveSubKey
:
448 resourceName
= "InvalidOperation_RegRemoveSubKey";
451 case ExceptionResource
.Arg_RegSubKeyAbsent
:
452 resourceName
= "Arg_RegSubKeyAbsent";
455 case ExceptionResource
.Arg_RegSubKeyValueAbsent
:
456 resourceName
= "Arg_RegSubKeyValueAbsent";
459 case ExceptionResource
.Arg_RegKeyDelHive
:
460 resourceName
= "Arg_RegKeyDelHive";
463 case ExceptionResource
.Security_RegistryPermission
:
464 resourceName
= "Security_RegistryPermission";
467 case ExceptionResource
.Arg_RegSetStrArrNull
:
468 resourceName
= "Arg_RegSetStrArrNull";
471 case ExceptionResource
.Arg_RegSetMismatchedKind
:
472 resourceName
= "Arg_RegSetMismatchedKind";
475 case ExceptionResource
.UnauthorizedAccess_RegistryNoWrite
:
476 resourceName
= "UnauthorizedAccess_RegistryNoWrite";
479 case ExceptionResource
.ObjectDisposed_RegKeyClosed
:
480 resourceName
= "ObjectDisposed_RegKeyClosed";
483 case ExceptionResource
.Arg_RegKeyStrLenBug
:
484 resourceName
= "Arg_RegKeyStrLenBug";
487 case ExceptionResource
.Argument_InvalidRegistryKeyPermissionCheck
:
488 resourceName
= "Argument_InvalidRegistryKeyPermissionCheck";
491 case ExceptionResource
.NotSupported_InComparableType
:
492 resourceName
= "NotSupported_InComparableType";
495 case ExceptionResource
.Argument_InvalidRegistryOptionsCheck
:
496 resourceName
= "Argument_InvalidRegistryOptionsCheck";
499 case ExceptionResource
.Argument_InvalidRegistryViewCheck
:
500 resourceName
= "Argument_InvalidRegistryViewCheck";
504 Contract
.Assert( false, "The enum value is not defined, please checked ExceptionArgumentName Enum.");
514 // The convention for this enum is using the argument name as the enum name
516 internal enum ExceptionArgument
{
519 dictionaryCreationThreshold
,
555 // The convention for this enum is using the resource name as the enum name
557 internal enum ExceptionResource
{
558 Argument_ImplementIComparable
,
559 Argument_InvalidType
,
560 Argument_InvalidArgumentForComparison
,
561 Argument_InvalidRegistryKeyPermissionCheck
,
562 ArgumentOutOfRange_NeedNonNegNum
,
564 Arg_ArrayPlusOffTooSmall
,
565 Arg_NonZeroLowerBound
,
566 Arg_RankMultiDimNotSupported
,
569 Arg_RegSetStrArrNull
,
570 Arg_RegSetMismatchedKind
,
572 Arg_RegSubKeyValueAbsent
,
574 Argument_AddingDuplicate
,
575 Serialization_InvalidOnDeser
,
576 Serialization_MissingKeys
,
577 Serialization_NullKey
,
578 Argument_InvalidArrayType
,
579 NotSupported_KeyCollectionSet
,
580 NotSupported_ValueCollectionSet
,
581 ArgumentOutOfRange_SmallCapacity
,
582 ArgumentOutOfRange_Index
,
583 Argument_InvalidOffLen
,
584 Argument_ItemNotExist
,
585 ArgumentOutOfRange_Count
,
586 ArgumentOutOfRange_InvalidThreshold
,
587 ArgumentOutOfRange_ListInsert
,
588 NotSupported_ReadOnlyCollection
,
589 InvalidOperation_CannotRemoveFromStackOrQueue
,
590 InvalidOperation_EmptyQueue
,
591 InvalidOperation_EnumOpCantHappen
,
592 InvalidOperation_EnumFailedVersion
,
593 InvalidOperation_EmptyStack
,
594 ArgumentOutOfRange_BiggerThanCollection
,
595 InvalidOperation_EnumNotStarted
,
596 InvalidOperation_EnumEnded
,
597 NotSupported_SortedListNestedWrite
,
598 InvalidOperation_NoValue
,
599 InvalidOperation_RegRemoveSubKey
,
600 Security_RegistryPermission
,
601 UnauthorizedAccess_RegistryNoWrite
,
602 ObjectDisposed_RegKeyClosed
,
603 NotSupported_InComparableType
,
604 Argument_InvalidRegistryOptionsCheck
,
605 Argument_InvalidRegistryViewCheck
,
606 TaskT_TransitionToFinal_AlreadyCompleted
,
607 TaskCompletionSourceT_TrySetException_NullException
,
608 TaskCompletionSourceT_TrySetException_NoExceptions
,