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.");
310 private static ArgumentOutOfRangeException
GetArgumentOutOfRangeException(ExceptionArgument argument
, ExceptionResource resource
)
312 return new ArgumentOutOfRangeException(GetArgumentName(argument
), resource
.ToString());
315 internal static void ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index()
317 throw GetArgumentOutOfRangeException(ExceptionArgument
.startIndex
,
318 ExceptionResource
.ArgumentOutOfRange_Index
);
321 internal static void ThrowCountArgumentOutOfRange_ArgumentOutOfRange_Count()
323 throw GetArgumentOutOfRangeException(ExceptionArgument
.count
,
324 ExceptionResource
.ArgumentOutOfRange_Count
);
328 // This function will convert an ExceptionResource enum value to the resource string.
330 internal static string GetResourceName(ExceptionResource resource
) {
331 string resourceName
= null;
334 case ExceptionResource
.Argument_ImplementIComparable
:
335 resourceName
= "Argument_ImplementIComparable";
338 case ExceptionResource
.Argument_AddingDuplicate
:
339 resourceName
= "Argument_AddingDuplicate";
342 case ExceptionResource
.ArgumentOutOfRange_BiggerThanCollection
:
343 resourceName
= "ArgumentOutOfRange_BiggerThanCollection";
346 case ExceptionResource
.ArgumentOutOfRange_Count
:
347 resourceName
= "ArgumentOutOfRange_Count";
350 case ExceptionResource
.ArgumentOutOfRange_Index
:
351 resourceName
= "ArgumentOutOfRange_Index";
354 case ExceptionResource
.ArgumentOutOfRange_InvalidThreshold
:
355 resourceName
= "ArgumentOutOfRange_InvalidThreshold";
358 case ExceptionResource
.ArgumentOutOfRange_ListInsert
:
359 resourceName
= "ArgumentOutOfRange_ListInsert";
362 case ExceptionResource
.ArgumentOutOfRange_NeedNonNegNum
:
363 resourceName
= "ArgumentOutOfRange_NeedNonNegNum";
366 case ExceptionResource
.ArgumentOutOfRange_SmallCapacity
:
367 resourceName
= "ArgumentOutOfRange_SmallCapacity";
370 case ExceptionResource
.Arg_ArrayPlusOffTooSmall
:
371 resourceName
= "Arg_ArrayPlusOffTooSmall";
374 case ExceptionResource
.Arg_RankMultiDimNotSupported
:
375 resourceName
= "Arg_RankMultiDimNotSupported";
378 case ExceptionResource
.Arg_NonZeroLowerBound
:
379 resourceName
= "Arg_NonZeroLowerBound";
382 case ExceptionResource
.Argument_InvalidArrayType
:
383 resourceName
= "Argument_InvalidArrayType";
386 case ExceptionResource
.Argument_InvalidOffLen
:
387 resourceName
= "Argument_InvalidOffLen";
390 case ExceptionResource
.Argument_ItemNotExist
:
391 resourceName
= "Argument_ItemNotExist";
394 case ExceptionResource
.InvalidOperation_CannotRemoveFromStackOrQueue
:
395 resourceName
= "InvalidOperation_CannotRemoveFromStackOrQueue";
398 case ExceptionResource
.InvalidOperation_EmptyQueue
:
399 resourceName
= "InvalidOperation_EmptyQueue";
402 case ExceptionResource
.InvalidOperation_EnumOpCantHappen
:
403 resourceName
= "InvalidOperation_EnumOpCantHappen";
406 case ExceptionResource
.InvalidOperation_EnumFailedVersion
:
407 resourceName
= "InvalidOperation_EnumFailedVersion";
410 case ExceptionResource
.InvalidOperation_EmptyStack
:
411 resourceName
= "InvalidOperation_EmptyStack";
414 case ExceptionResource
.InvalidOperation_EnumNotStarted
:
415 resourceName
= "InvalidOperation_EnumNotStarted";
418 case ExceptionResource
.InvalidOperation_EnumEnded
:
419 resourceName
= "InvalidOperation_EnumEnded";
422 case ExceptionResource
.NotSupported_KeyCollectionSet
:
423 resourceName
= "NotSupported_KeyCollectionSet";
426 case ExceptionResource
.NotSupported_ReadOnlyCollection
:
427 resourceName
= "NotSupported_ReadOnlyCollection";
430 case ExceptionResource
.NotSupported_ValueCollectionSet
:
431 resourceName
= "NotSupported_ValueCollectionSet";
435 case ExceptionResource
.NotSupported_SortedListNestedWrite
:
436 resourceName
= "NotSupported_SortedListNestedWrite";
440 case ExceptionResource
.Serialization_InvalidOnDeser
:
441 resourceName
= "Serialization_InvalidOnDeser";
444 case ExceptionResource
.Serialization_MissingKeys
:
445 resourceName
= "Serialization_MissingKeys";
448 case ExceptionResource
.Serialization_NullKey
:
449 resourceName
= "Serialization_NullKey";
452 case ExceptionResource
.Argument_InvalidType
:
453 resourceName
= "Argument_InvalidType";
456 case ExceptionResource
.Argument_InvalidArgumentForComparison
:
457 resourceName
= "Argument_InvalidArgumentForComparison";
460 case ExceptionResource
.InvalidOperation_NoValue
:
461 resourceName
= "InvalidOperation_NoValue";
464 case ExceptionResource
.InvalidOperation_RegRemoveSubKey
:
465 resourceName
= "InvalidOperation_RegRemoveSubKey";
468 case ExceptionResource
.Arg_RegSubKeyAbsent
:
469 resourceName
= "Arg_RegSubKeyAbsent";
472 case ExceptionResource
.Arg_RegSubKeyValueAbsent
:
473 resourceName
= "Arg_RegSubKeyValueAbsent";
476 case ExceptionResource
.Arg_RegKeyDelHive
:
477 resourceName
= "Arg_RegKeyDelHive";
480 case ExceptionResource
.Security_RegistryPermission
:
481 resourceName
= "Security_RegistryPermission";
484 case ExceptionResource
.Arg_RegSetStrArrNull
:
485 resourceName
= "Arg_RegSetStrArrNull";
488 case ExceptionResource
.Arg_RegSetMismatchedKind
:
489 resourceName
= "Arg_RegSetMismatchedKind";
492 case ExceptionResource
.UnauthorizedAccess_RegistryNoWrite
:
493 resourceName
= "UnauthorizedAccess_RegistryNoWrite";
496 case ExceptionResource
.ObjectDisposed_RegKeyClosed
:
497 resourceName
= "ObjectDisposed_RegKeyClosed";
500 case ExceptionResource
.Arg_RegKeyStrLenBug
:
501 resourceName
= "Arg_RegKeyStrLenBug";
504 case ExceptionResource
.Argument_InvalidRegistryKeyPermissionCheck
:
505 resourceName
= "Argument_InvalidRegistryKeyPermissionCheck";
508 case ExceptionResource
.NotSupported_InComparableType
:
509 resourceName
= "NotSupported_InComparableType";
512 case ExceptionResource
.Argument_InvalidRegistryOptionsCheck
:
513 resourceName
= "Argument_InvalidRegistryOptionsCheck";
516 case ExceptionResource
.Argument_InvalidRegistryViewCheck
:
517 resourceName
= "Argument_InvalidRegistryViewCheck";
521 Contract
.Assert( false, "The enum value is not defined, please checked ExceptionArgumentName Enum.");
531 // The convention for this enum is using the argument name as the enum name
533 internal enum ExceptionArgument
{
536 dictionaryCreationThreshold
,
574 // The convention for this enum is using the resource name as the enum name
576 internal enum ExceptionResource
{
577 Argument_ImplementIComparable
,
578 Argument_InvalidType
,
579 Argument_InvalidArgumentForComparison
,
580 Argument_InvalidRegistryKeyPermissionCheck
,
581 ArgumentOutOfRange_NeedNonNegNum
,
583 Arg_ArrayPlusOffTooSmall
,
584 Arg_NonZeroLowerBound
,
585 Arg_RankMultiDimNotSupported
,
588 Arg_RegSetStrArrNull
,
589 Arg_RegSetMismatchedKind
,
591 Arg_RegSubKeyValueAbsent
,
593 Argument_AddingDuplicate
,
594 Serialization_InvalidOnDeser
,
595 Serialization_MissingKeys
,
596 Serialization_NullKey
,
597 Argument_InvalidArrayType
,
598 NotSupported_KeyCollectionSet
,
599 NotSupported_ValueCollectionSet
,
600 ArgumentOutOfRange_SmallCapacity
,
601 ArgumentOutOfRange_Index
,
602 Argument_InvalidOffLen
,
603 Argument_ItemNotExist
,
604 ArgumentOutOfRange_Count
,
605 ArgumentOutOfRange_InvalidThreshold
,
606 ArgumentOutOfRange_ListInsert
,
607 NotSupported_ReadOnlyCollection
,
608 InvalidOperation_CannotRemoveFromStackOrQueue
,
609 InvalidOperation_EmptyQueue
,
610 InvalidOperation_EnumOpCantHappen
,
611 InvalidOperation_EnumFailedVersion
,
612 InvalidOperation_EmptyStack
,
613 ArgumentOutOfRange_BiggerThanCollection
,
614 InvalidOperation_EnumNotStarted
,
615 InvalidOperation_EnumEnded
,
616 NotSupported_SortedListNestedWrite
,
617 InvalidOperation_NoValue
,
618 InvalidOperation_RegRemoveSubKey
,
619 Security_RegistryPermission
,
620 UnauthorizedAccess_RegistryNoWrite
,
621 ObjectDisposed_RegKeyClosed
,
622 NotSupported_InComparableType
,
623 Argument_InvalidRegistryOptionsCheck
,
624 Argument_InvalidRegistryViewCheck
,
625 TaskT_TransitionToFinal_AlreadyCompleted
,
626 TaskCompletionSourceT_TrySetException_NullException
,
627 TaskCompletionSourceT_TrySetException_NoExceptions
,