-
Notifications
You must be signed in to change notification settings - Fork 1.9k
/
Contracts.cs
1001 lines (920 loc) · 42.6 KB
/
Contracts.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#pragma warning disable 420 // volatile with Interlocked.CompareExchange
// We want the conditional code in this file to always be available to
// client assemblies that might be DEBUG versions. That is, if someone uses
// the release build of this assembly to build a DEBUG version of their code,
// we want Contracts.Assert to be fully functional for that client.
#define DEBUG
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Threading;
#if CPUMATH_INFRASTRUCTURE
namespace Microsoft.ML.Internal.CpuMath.Core
#else
namespace Microsoft.ML
#endif
{
using Conditional = System.Diagnostics.ConditionalAttribute;
using Debug = System.Diagnostics.Debug;
/// <summary>
/// Interface for "processing" exceptions before they are thrown. This can
/// be used to add context to the exception, wrap the exception in another one,
/// totally replace the exception, etc. It is not legal to return null from
/// Process (unless null was passed in, which really shouldn't happen).
/// </summary>
#if CPUMATH_INFRASTRUCTURE
internal interface IExceptionContext
#else
public interface IExceptionContext
#endif
{
TException Process<TException>(TException ex)
where TException : Exception;
/// <summary>
/// A string describing the context itself.
/// </summary>
string ContextDescription { get; }
}
#if CPUMATH_INFRASTRUCTURE
[Flags]
internal enum MessageSensitivity
{
None = 0,
Unknown = ~None
}
#endif
[BestFriend]
internal static partial class Contracts
{
public const string IsMarkedKey = "ML_IsMarked";
public const string SensitivityKey = "ML_Sensitivity";
// This is the assert handler. Typically unit tests set a handler that throws
// a test failure.
private static volatile Action<string, IExceptionContext> _handler;
private static string GetMsg(string msg, params object[] args)
{
try
{
msg = string.Format(CultureInfo.InvariantCulture, msg, args);
}
catch (FormatException ex)
{
Contracts.Assert(false, "Format string arg mismatch: " + ex.Message);
}
return msg;
}
private static int Size<T>(ICollection<T> c)
{
return c == null ? 0 : c.Count;
}
/// <summary>
/// Does standard processing of an exception (typically called after construction
/// but before it is thrown).
/// </summary>
public static TException Process<TException>(this TException ex, IExceptionContext ectx = null)
where TException : Exception
{
AssertValue(ex);
AssertValueOrNull(ectx);
ex = ectx != null ? ectx.Process(ex) : Mark(ex);
return ex;
}
/// <summary>
/// Mark the exception by setting <see cref="IsMarkedKey"/> in the exception
/// <see cref="Exception.Data"/> to 1.
/// </summary>
public static TException Mark<TException>(TException ex)
where TException : Exception
{
AssertValue(ex);
ex.Data[IsMarkedKey] = 1;
return ex;
}
/// <summary>
/// Indicates whether the exception was "marked" the Contracts code.
/// </summary>
public static bool IsMarked(this Exception ex)
{
AssertValue(ex);
return ex.Data.Contains(IsMarkedKey);
}
/// <summary>
/// Exceptions whose message communicates potentially sensitive information should be
/// marked using this method, before they are thrown. Note that if the exception already
/// had this flag set, the message will be flagged with the bitwise or of the existing
/// flag, alongside the passed in sensivity.
/// </summary>
public static TException MarkSensitive<TException>(this TException ex, MessageSensitivity sensitivity)
where TException : Exception
{
AssertValue(ex);
MessageSensitivity innerSensitivity;
if (!ex.Data.Contains(SensitivityKey))
innerSensitivity = MessageSensitivity.None;
else
innerSensitivity = (ex.Data[SensitivityKey] as MessageSensitivity?) ?? MessageSensitivity.None;
ex.Data[SensitivityKey] = innerSensitivity | sensitivity;
return ex;
}
/// <summary>
/// This is a convenience method to get the sensitivity of an exception,
/// as encoded with <see cref="SensitivityKey"/>. If there is no key, then
/// the message is assumed to be of unknown sensitivity, i.e., it is assumed
/// that it might contain literally anything.
/// </summary>
/// <param name="ex">The exception to query</param>
/// <returns>The value encoded at the <see cref="SensitivityKey"/>, if it is
/// a <see cref="MessageSensitivity"/> value. If neither of these conditions
/// hold then <see cref="MessageSensitivity.Unknown"/> is returned.</returns>
public static MessageSensitivity Sensitivity(this Exception ex)
{
AssertValue(ex);
if (!ex.Data.Contains(SensitivityKey))
return MessageSensitivity.Unknown;
return (ex.Data[SensitivityKey] as MessageSensitivity?) ?? MessageSensitivity.Unknown;
}
#if !CPUMATH_INFRASTRUCTURE
/// <summary>
/// This is an internal convenience implementation of an exception context to make marking
/// exceptions with a specific sensitivity flag a bit less onorous. The alternative to a scheme
/// like this, where messages are marked through use of <see cref="Process{TException}(TException)"/>,
/// would be that every check and exception method in this file would need some "peer" where
/// sensitivity was set. Since there are so many, we have this method instead. I'm not sure if
/// there will be performance implications. There shouldn't be, since checks rarely happen in
/// tight loops.
/// </summary>
private readonly struct SensitiveExceptionContext : IExceptionContext
{
/// <summary>
/// We will run this instances <see cref="IExceptionContext.Process{TException}(TException)"/> first.
/// This can be null.
/// </summary>
public readonly IExceptionContext Inner;
/// <summary>
/// Exceptions will be marked with this. If <see cref="Inner"/> happens to mark it with a sensivity
/// flag, then the result will not only be this value, but the bitwise or of this with the existing
/// value.
/// </summary>
public readonly MessageSensitivity ToMark;
public string ContextDescription => Inner?.ContextDescription ?? "";
public SensitiveExceptionContext(IExceptionContext inner, MessageSensitivity toMark)
{
AssertValueOrNull(inner);
Inner = inner;
ToMark = toMark;
}
public TException Process<TException>(TException ex) where TException : Exception
{
CheckValue(ex, nameof(ex));
ex = Inner?.Process(ex) ?? ex;
return ex.MarkSensitive(ToMark);
}
}
/// <summary>
/// A convenience context for marking exceptions from checks and excepts with <see cref="MessageSensitivity.None"/>.
/// </summary>
public static IExceptionContext NotSensitive() => NotSensitive(null);
// REVIEW: The above could be a property, but then it would look unlike the
// extension method, and extension properties are still not a thing as of C# 7.2. :(
/// <summary>
/// A convenience context for marking exceptions from checks and excepts with <see cref="MessageSensitivity.None"/>.
/// </summary>
public static IExceptionContext NotSensitive(this IExceptionContext ctx)
=> new SensitiveExceptionContext(ctx, MessageSensitivity.None);
/// <summary>
/// A convenience context for marking exceptions from checks and excepts with <see cref="MessageSensitivity.UserData"/>.
/// </summary>
public static IExceptionContext UserSensitive() => UserSensitive(null);
/// <summary>
/// A convenience context for marking exceptions from checks and excepts with <see cref="MessageSensitivity.UserData"/>.
/// </summary>
public static IExceptionContext UserSensitive(this IExceptionContext ctx)
=> new SensitiveExceptionContext(ctx, MessageSensitivity.UserData);
/// <summary>
/// A convenience context for marking exceptions from checks and excepts with <see cref="MessageSensitivity.Schema"/>.
/// </summary>
public static IExceptionContext SchemaSensitive() => SchemaSensitive(null);
/// <summary>
/// A convenience context for marking exceptions from checks and excepts with <see cref="MessageSensitivity.Schema"/>.
/// </summary>
public static IExceptionContext SchemaSensitive(this IExceptionContext ctx)
=> new SensitiveExceptionContext(ctx, MessageSensitivity.Schema);
#endif
/// <summary>
/// Sets the assert handler to the given function, returning the previous handler.
/// </summary>
public static Action<string, IExceptionContext> SetAssertHandler(Action<string, IExceptionContext> handler)
{
return Interlocked.Exchange(ref _handler, handler);
}
// Standard Exception generation. Note that these do NOT throw the exception,
// merely construct (and log) it.
// NOTE: The ordering of arguments to these is standardized to be (when they exist):
// * inner exception
// * parameter value of type T
// * parameter name
// * message composition - either a single string or format followed by params array
// Default exception type (currently InvalidOperationException)
/// <summary>
/// Default exception type (currently InvalidOperationException)
/// </summary>
public static Exception Except()
=> Process(new InvalidOperationException());
public static Exception Except(this IExceptionContext ctx)
=> Process(new InvalidOperationException(), ctx);
public static Exception Except(string msg)
=> Process(new InvalidOperationException(msg));
public static Exception Except(this IExceptionContext ctx, string msg)
=> Process(new InvalidOperationException(msg), ctx);
public static Exception Except(string msg, params object[] args)
=> Process(new InvalidOperationException(GetMsg(msg, args)));
public static Exception Except(this IExceptionContext ctx, string msg, params object[] args)
=> Process(new InvalidOperationException(GetMsg(msg, args)), ctx);
public static Exception Except(Exception inner, string msg)
=> Process(new InvalidOperationException(msg, inner));
public static Exception Except(this IExceptionContext ctx, Exception inner, string msg)
=> Process(new InvalidOperationException(msg, inner), ctx);
public static Exception Except(Exception inner, string msg, params object[] args)
=> Process(new InvalidOperationException(GetMsg(msg, args), inner));
public static Exception Except(this IExceptionContext ctx, Exception inner, string msg, params object[] args)
=> Process(new InvalidOperationException(GetMsg(msg, args), inner), ctx);
// REVIEW: Change ExceptUser*** to use a custom exception type.
/// <summary>
/// For signalling bad user input.
/// </summary>
public static Exception ExceptUserArg(string name)
=> Process(new ArgumentOutOfRangeException(name));
public static Exception ExceptUserArg(this IExceptionContext ctx, string name)
=> Process(new ArgumentOutOfRangeException(name), ctx);
public static Exception ExceptUserArg(string name, string msg)
=> Process(new ArgumentOutOfRangeException(name, msg));
public static Exception ExceptUserArg(this IExceptionContext ctx, string name, string msg)
=> Process(new ArgumentOutOfRangeException(name, msg), ctx);
public static Exception ExceptUserArg(string name, string msg, params object[] args)
=> Process(new ArgumentOutOfRangeException(name, GetMsg(msg, args)));
public static Exception ExceptUserArg(this IExceptionContext ctx, string name, string msg, params object[] args)
=> Process(new ArgumentOutOfRangeException(name, GetMsg(msg, args)), ctx);
/// <summary>
/// For signalling bad function parameters.
/// </summary>
public static Exception ExceptParam(string paramName)
=> Process(new ArgumentOutOfRangeException(paramName));
public static Exception ExceptParam(this IExceptionContext ctx, string paramName)
=> Process(new ArgumentOutOfRangeException(paramName), ctx);
public static Exception ExceptParam(string paramName, string msg)
=> Process(new ArgumentOutOfRangeException(paramName, msg));
public static Exception ExceptParam(this IExceptionContext ctx, string paramName, string msg)
=> Process(new ArgumentOutOfRangeException(paramName, msg), ctx);
public static Exception ExceptParam(string paramName, string msg, params object[] args)
=> Process(new ArgumentOutOfRangeException(paramName, GetMsg(msg, args)));
public static Exception ExceptParam(this IExceptionContext ctx, string paramName, string msg, params object[] args)
=> Process(new ArgumentOutOfRangeException(paramName, GetMsg(msg, args)), ctx);
public static Exception ExceptParamValue<T>(T value, string paramName, string msg)
=> Process(new ArgumentOutOfRangeException(msg, value, paramName));
public static Exception ExceptParamValue<T>(this IExceptionContext ctx, T value, string paramName, string msg)
=> Process(new ArgumentOutOfRangeException(msg, value, paramName), ctx);
public static Exception ExceptParamValue<T>(T value, string paramName, string msg, params object[] args)
=> Process(new ArgumentOutOfRangeException(paramName, value, GetMsg(msg, args)));
public static Exception ExceptParamValue<T>(this IExceptionContext ctx, T value, string paramName, string msg, params object[] args)
=> Process(new ArgumentOutOfRangeException(paramName, value, GetMsg(msg, args)), ctx);
/// <summary>
/// For signalling null function parameters.
/// </summary>
public static Exception ExceptValue(string paramName)
=> Process(new ArgumentNullException(paramName));
public static Exception ExceptValue(this IExceptionContext ctx, string paramName)
=> Process(new ArgumentNullException(paramName), ctx);
public static Exception ExceptValue(string paramName, string msg)
=> Process(new ArgumentNullException(paramName, msg));
public static Exception ExceptValue(this IExceptionContext ctx, string paramName, string msg)
=> Process(new ArgumentNullException(paramName, msg), ctx);
public static Exception ExceptValue(string paramName, string msg, params object[] args)
=> Process(new ArgumentNullException(paramName, GetMsg(msg, args)));
public static Exception ExceptValue(this IExceptionContext ctx, string paramName, string msg, params object[] args)
=> Process(new ArgumentNullException(paramName, GetMsg(msg, args)), ctx);
// For signalling null or empty function parameters (strings, arrays, collections, etc).
/// <summary>
/// For signalling null or empty function parameters (strings, arrays, collections, etc).
/// </summary>
public static Exception ExceptEmpty(string paramName)
=> Process(new ArgumentOutOfRangeException(paramName, string.Format("{0} cannot be null or empty", paramName)));
public static Exception ExceptEmpty(this IExceptionContext ctx, string paramName)
=> Process(new ArgumentOutOfRangeException(paramName, string.Format("{0} cannot be null or empty", paramName)), ctx);
public static Exception ExceptEmpty(string paramName, string msg)
=> Process(new ArgumentOutOfRangeException(paramName, msg));
public static Exception ExceptEmpty(this IExceptionContext ctx, string paramName, string msg)
=> Process(new ArgumentOutOfRangeException(paramName, msg), ctx);
public static Exception ExceptEmpty(string paramName, string msg, params object[] args)
=> Process(new ArgumentOutOfRangeException(paramName, GetMsg(msg, args)));
public static Exception ExceptEmpty(this IExceptionContext ctx, string paramName, string msg, params object[] args)
=> Process(new ArgumentOutOfRangeException(paramName, GetMsg(msg, args)), ctx);
/// <summary>
/// For signalling null, empty or white-space function parameters (strings, arrays, collections, etc).
/// </summary>
public static Exception ExceptWhiteSpace(string paramName)
=> Process(new ArgumentOutOfRangeException(paramName, string.Format("{0} cannot be null or white space", paramName)));
public static Exception ExceptWhiteSpace(this IExceptionContext ctx, string paramName)
=> Process(new ArgumentOutOfRangeException(paramName, string.Format("{0} cannot be null or white space", paramName)), ctx);
public static Exception ExceptWhiteSpace(string paramName, string msg)
=> Process(new ArgumentOutOfRangeException(paramName, msg));
public static Exception ExceptWhiteSpace(this IExceptionContext ctx, string paramName, string msg)
=> Process(new ArgumentOutOfRangeException(paramName, msg), ctx);
/// <summary>
/// For signalling errors in decoding information, whether while reading from a file,
/// parsing user input, etc.
/// </summary>
/// <returns></returns>
public static Exception ExceptDecode()
=> Process(new FormatException());
public static Exception ExceptDecode(this IExceptionContext ctx)
=> Process(new FormatException(), ctx);
public static Exception ExceptDecode(string msg)
=> Process(new FormatException(msg));
public static Exception ExceptDecode(this IExceptionContext ctx, string msg)
=> Process(new FormatException(msg), ctx);
public static Exception ExceptDecode(string msg, params object[] args)
=> Process(new FormatException(GetMsg(msg, args)));
public static Exception ExceptDecode(this IExceptionContext ctx, string msg, params object[] args)
=> Process(new FormatException(GetMsg(msg, args)), ctx);
public static Exception ExceptDecode(Exception inner, string msg)
=> Process(new FormatException(msg, inner));
public static Exception ExceptDecode(this IExceptionContext ctx, Exception inner, string msg)
=> Process(new FormatException(msg, inner), ctx);
public static Exception ExceptDecode(Exception inner, string msg, params object[] args)
=> Process(new FormatException(GetMsg(msg, args), inner));
public static Exception ExceptDecode(this IExceptionContext ctx, Exception inner, string msg, params object[] args)
=> Process(new FormatException(GetMsg(msg, args), inner), ctx);
/// <summary>
/// For signalling IO failures.
/// </summary>
public static Exception ExceptIO()
=> Process(new IOException());
public static Exception ExceptIO(this IExceptionContext ctx)
=> Process(new IOException(), ctx);
public static Exception ExceptIO(string msg)
=> Process(new IOException(msg));
public static Exception ExceptIO(this IExceptionContext ctx, string msg)
=> Process(new IOException(msg), ctx);
public static Exception ExceptIO(string msg, params object[] args)
=> Process(new IOException(GetMsg(msg, args)));
public static Exception ExceptIO(this IExceptionContext ctx, string msg, params object[] args)
=> Process(new IOException(GetMsg(msg, args)), ctx);
public static Exception ExceptIO(Exception inner, string msg)
=> Process(new IOException(msg, inner));
public static Exception ExceptIO(this IExceptionContext ctx, Exception inner, string msg)
=> Process(new IOException(msg, inner), ctx);
public static Exception ExceptIO(Exception inner, string msg, params object[] args)
=> Process(new IOException(GetMsg(msg, args), inner));
public static Exception ExceptIO(this IExceptionContext ctx, Exception inner, string msg, params object[] args)
=> Process(new IOException(GetMsg(msg, args), inner), ctx);
/// <summary>
/// For signalling functionality that is not YET implemented.
/// </summary>
public static Exception ExceptNotImpl()
=> Process(new NotImplementedException());
public static Exception ExceptNotImpl(this IExceptionContext ctx)
=> Process(new NotImplementedException(), ctx);
public static Exception ExceptNotImpl(string msg)
=> Process(new NotImplementedException(msg));
public static Exception ExceptNotImpl(this IExceptionContext ctx, string msg)
=> Process(new NotImplementedException(msg), ctx);
public static Exception ExceptNotImpl(string msg, params object[] args)
=> Process(new NotImplementedException(GetMsg(msg, args)));
public static Exception ExceptNotImpl(this IExceptionContext ctx, string msg, params object[] args)
=> Process(new NotImplementedException(GetMsg(msg, args)), ctx);
/// <summary>
/// For signalling functionality that is not implemented by design.
/// </summary>
public static Exception ExceptNotSupp()
=> Process(new NotSupportedException());
public static Exception ExceptNotSupp(this IExceptionContext ctx)
=> Process(new NotSupportedException(), ctx);
public static Exception ExceptNotSupp(string msg)
=> Process(new NotSupportedException(msg));
public static Exception ExceptNotSupp(this IExceptionContext ctx, string msg)
=> Process(new NotSupportedException(msg), ctx);
public static Exception ExceptNotSupp(string msg, params object[] args)
=> Process(new NotSupportedException(GetMsg(msg, args)));
public static Exception ExceptNotSupp(this IExceptionContext ctx, string msg, params object[] args)
=> Process(new NotSupportedException(GetMsg(msg, args)), ctx);
/// <summary>
/// For signalling schema validation issues.
/// </summary>
public static Exception ExceptSchemaMismatch(string paramName, string columnRole, string columnName)
=> Process(new ArgumentOutOfRangeException(paramName, MakeSchemaMismatchMsg(columnRole, columnName)));
public static Exception ExceptSchemaMismatch(this IExceptionContext ctx, string paramName, string columnRole, string columnName)
=> Process(new ArgumentOutOfRangeException(paramName, MakeSchemaMismatchMsg(columnRole, columnName)), ctx);
public static Exception ExceptSchemaMismatch(string paramName, string columnRole, string columnName, string expectedType, string actualType)
=> Process(new ArgumentOutOfRangeException(paramName, MakeSchemaMismatchMsg(columnRole, columnName, expectedType, actualType)));
public static Exception ExceptSchemaMismatch(this IExceptionContext ctx, string paramName, string columnRole, string columnName, string expectedType, string actualType)
=> Process(new ArgumentOutOfRangeException(paramName, MakeSchemaMismatchMsg(columnRole, columnName, expectedType, actualType)), ctx);
private static string MakeSchemaMismatchMsg(string columnRole, string columnName, string expectedType = null, string actualType = null)
{
if (actualType == null)
return $"Could not find {columnRole} column '{columnName}'";
return $"Schema mismatch for {columnRole} column '{columnName}': expected {expectedType}, got {actualType}";
}
// Check - these check a condition and if it fails, throw the corresponding exception.
// NOTE: The ordering of arguments to these is standardized to be:
// * boolean condition
// * parameter name
// * parameter value
// * message string
//
// Note that these do NOT support a params array of arguments since that would
// involve memory allocation whenever the condition is checked. When message string
// args are need, the condition test should be inlined, eg:
// if (!condition)
// throw Contracts.ExceptXxx(fmt, arg1, arg2);
public static void Check(bool f)
{
if (!f)
throw Except();
}
public static void Check(this IExceptionContext ctx, bool f)
{
if (!f)
throw Except(ctx);
}
public static void Check(bool f, string msg)
{
if (!f)
throw Except(msg);
}
public static void Check(this IExceptionContext ctx, bool f, string msg)
{
if (!f)
throw Except(ctx, msg);
}
/// <summary>
/// CheckUserArg / ExceptUserArg should be used when the validation of user-provided arguments failed.
/// Typically, this is shortly after the arguments are parsed using CmdParser.
/// </summary>
public static void CheckUserArg(bool f, string name)
{
if (!f)
throw ExceptUserArg(name);
}
public static void CheckUserArg(this IExceptionContext ctx, bool f, string name)
{
if (!f)
throw ExceptUserArg(ctx, name);
}
public static void CheckUserArg(bool f, string name, string msg)
{
if (!f)
throw ExceptUserArg(name, msg);
}
public static void CheckUserArg(this IExceptionContext ctx, bool f, string name, string msg)
{
if (!f)
throw ExceptUserArg(ctx, name, msg);
}
public static void CheckParam(bool f, string paramName)
{
if (!f)
throw ExceptParam(paramName);
}
public static void CheckParam(this IExceptionContext ctx, bool f, string paramName)
{
if (!f)
throw ExceptParam(ctx, paramName);
}
public static void CheckParam(bool f, string paramName, string msg)
{
if (!f)
throw ExceptParam(paramName, msg);
}
public static void CheckParam(this IExceptionContext ctx, bool f, string paramName, string msg)
{
if (!f)
throw ExceptParam(ctx, paramName, msg);
}
public static void CheckParamValue<T>(bool f, T value, string paramName, string msg)
{
if (!f)
throw ExceptParamValue(value, paramName, msg);
}
public static void CheckParamValue<T>(this IExceptionContext ctx, bool f, T value, string paramName, string msg)
{
if (!f)
throw ExceptParamValue(ctx, value, paramName, msg);
}
public static T CheckRef<T>(T val, string paramName) where T : class
{
if (object.ReferenceEquals(val, null))
throw ExceptValue(paramName);
return val;
}
public static T CheckRef<T>(this IExceptionContext ctx, T val, string paramName) where T : class
{
if (object.ReferenceEquals(val, null))
throw ExceptValue(ctx, paramName);
return val;
}
public static T CheckRef<T>(this IExceptionContext ctx, T val, string paramName, string msg) where T : class
{
if (object.ReferenceEquals(val, null))
throw ExceptValue(ctx, paramName, msg);
return val;
}
public static void CheckValue<T>(T val, string paramName) where T : class
{
if (object.ReferenceEquals(val, null))
throw ExceptValue(paramName);
}
public static void CheckValue<T>(this IExceptionContext ctx, T val, string paramName) where T : class
{
if (object.ReferenceEquals(val, null))
throw ExceptValue(ctx, paramName);
}
public static T CheckValue<T>(T val, string paramName, string msg) where T : class
{
if (object.ReferenceEquals(val, null))
throw ExceptValue(paramName, msg);
return val;
}
public static T CheckValue<T>(this IExceptionContext ctx, T val, string paramName, string msg) where T : class
{
if (object.ReferenceEquals(val, null))
throw ExceptValue(ctx, paramName, msg);
return val;
}
public static string CheckNonEmpty(string s, string paramName)
{
if (string.IsNullOrEmpty(s))
throw ExceptEmpty(paramName);
return s;
}
public static string CheckNonEmpty(this IExceptionContext ctx, string s, string paramName)
{
if (string.IsNullOrEmpty(s))
throw ExceptEmpty(ctx, paramName);
return s;
}
public static string CheckNonWhiteSpace(string s, string paramName)
{
if (string.IsNullOrWhiteSpace(s))
throw ExceptWhiteSpace(paramName);
return s;
}
public static string CheckNonWhiteSpace(this IExceptionContext ctx, string s, string paramName)
{
if (string.IsNullOrWhiteSpace(s))
throw ExceptWhiteSpace(ctx, paramName);
return s;
}
public static string CheckNonEmpty(string s, string paramName, string msg)
{
if (string.IsNullOrEmpty(s))
throw ExceptEmpty(paramName, msg);
return s;
}
public static string CheckNonEmpty(this IExceptionContext ctx, string s, string paramName, string msg)
{
if (string.IsNullOrEmpty(s))
throw ExceptEmpty(ctx, paramName, msg);
return s;
}
public static string CheckNonWhiteSpace(string s, string paramName, string msg)
{
if (string.IsNullOrWhiteSpace(s))
throw ExceptWhiteSpace(paramName, msg);
return s;
}
public static string CheckNonWhiteSpace(this IExceptionContext ctx, string s, string paramName, string msg)
{
if (string.IsNullOrWhiteSpace(s))
throw ExceptWhiteSpace(ctx, paramName, msg);
return s;
}
public static T[] CheckNonEmpty<T>(T[] args, string paramName)
{
if (Size(args) == 0)
throw ExceptEmpty(paramName);
return args;
}
public static T[] CheckNonEmpty<T>(this IExceptionContext ctx, T[] args, string paramName)
{
if (Size(args) == 0)
throw ExceptEmpty(ctx, paramName);
return args;
}
public static T[] CheckNonEmpty<T>(T[] args, string paramName, string msg)
{
if (Size(args) == 0)
throw ExceptEmpty(paramName, msg);
return args;
}
public static T[] CheckNonEmpty<T>(this IExceptionContext ctx, T[] args, string paramName, string msg)
{
if (Size(args) == 0)
throw ExceptEmpty(ctx, paramName, msg);
return args;
}
public static ICollection<T> CheckNonEmpty<T>(ICollection<T> args, string paramName)
{
if (Size(args) == 0)
throw ExceptEmpty(paramName);
return args;
}
public static ICollection<T> CheckNonEmpty<T>(this IExceptionContext ctx, ICollection<T> args, string paramName)
{
if (Size(args) == 0)
throw ExceptEmpty(ctx, paramName);
return args;
}
public static ICollection<T> CheckNonEmpty<T>(ICollection<T> args, string paramName, string msg)
{
if (Size(args) == 0)
throw ExceptEmpty(paramName, msg);
return args;
}
public static ICollection<T> CheckNonEmpty<T>(this IExceptionContext ctx, ICollection<T> args, string paramName, string msg)
{
if (Size(args) == 0)
throw ExceptEmpty(ctx, paramName, msg);
return args;
}
public static void CheckDecode(bool f)
{
if (!f)
throw ExceptDecode();
}
public static void CheckDecode(this IExceptionContext ctx, bool f)
{
if (!f)
throw ExceptDecode(ctx);
}
public static void CheckDecode(bool f, string msg)
{
if (!f)
throw ExceptDecode(msg);
}
public static void CheckDecode(this IExceptionContext ctx, bool f, string msg)
{
if (!f)
throw ExceptDecode(ctx, msg);
}
public static void CheckIO(bool f)
{
if (!f)
throw ExceptIO();
}
public static void CheckIO(this IExceptionContext ctx, bool f)
{
if (!f)
throw ExceptIO(ctx);
}
public static void CheckIO(bool f, string msg)
{
if (!f)
throw ExceptIO(msg);
}
public static void CheckIO(this IExceptionContext ctx, bool f, string msg)
{
if (!f)
throw ExceptIO(ctx, msg);
}
#if !CPUMATH_INFRASTRUCTURE
/// <summary>
/// Check state of the host and throw exception if host marked to stop all exection.
/// </summary>
public static void CheckAlive(this IHostEnvironment env)
{
if (env.IsCancelled)
throw Process(new OperationCanceledException("Operation was cancelled."), env);
}
#endif
/// <summary>
/// This documents that the parameter can legally be null.
/// </summary>
[Conditional("INVARIANT_CHECKS")]
public static void CheckValueOrNull<T>(T val) where T : class
{
}
/// <summary>
/// This documents that the parameter can legally be null.
/// </summary>
[Conditional("INVARIANT_CHECKS")]
public static void CheckValueOrNull<T>(this IExceptionContext ctx, T val) where T : class
{
}
// Assert
#region Private assert handling
private static void DbgFailCore(string msg, IExceptionContext ctx = null)
{
var handler = _handler;
if (handler != null)
handler(msg, ctx);
else if (ctx != null)
Debug.Fail(msg, ctx.ContextDescription);
else
Debug.Fail(msg);
}
private static void DbgFail(IExceptionContext ctx = null)
{
DbgFailCore("Assertion Failed", ctx);
}
private static void DbgFail(string msg)
{
DbgFailCore(msg);
}
private static void DbgFail(IExceptionContext ctx, string msg)
{
DbgFailCore(msg, ctx);
}
private static void DbgFailValue(IExceptionContext ctx = null)
{
DbgFailCore("Non-null assertion failure", ctx);
}
private static void DbgFailValue(string paramName)
{
DbgFailCore(string.Format(CultureInfo.InvariantCulture, "Non-null assertion failure: {0}", paramName));
}
private static void DbgFailValue(IExceptionContext ctx, string paramName)
{
DbgFailCore(string.Format(CultureInfo.InvariantCulture, "Non-null assertion failure: {0}", paramName), ctx);
}
private static void DbgFailValue(string paramName, string msg)
{
DbgFailCore(string.Format(CultureInfo.InvariantCulture, "Non-null assertion failure: {0}: {1}", paramName, msg));
}
private static void DbgFailValue(IExceptionContext ctx, string paramName, string msg)
{
DbgFailCore(string.Format(CultureInfo.InvariantCulture, "Non-null assertion failure: {0}: {1}", paramName, msg), ctx);
}
private static void DbgFailEmpty(IExceptionContext ctx = null)
{
DbgFailCore("Non-empty assertion failure", ctx);
}
private static void DbgFailEmpty(string msg)
{
DbgFailCore(string.Format(CultureInfo.InvariantCulture, "Non-empty assertion failure: {0}", msg));
}
private static void DbgFailEmpty(IExceptionContext ctx, string msg)
{
DbgFailCore(string.Format(CultureInfo.InvariantCulture, "Non-empty assertion failure: {0}", msg), ctx);
}
#endregion Private assert handling
[Conditional("DEBUG")]
public static void Assert(bool f)
{
if (!f)
DbgFail();
}
[Conditional("DEBUG")]
public static void Assert(this IExceptionContext ctx, bool f)
{
if (!f)
DbgFail(ctx);
}
[Conditional("DEBUG")]
public static void Assert(bool f, string msg)
{
if (!f)
DbgFail(msg);
}
[Conditional("DEBUG")]
public static void Assert(this IExceptionContext ctx, bool f, string msg)
{
if (!f)
DbgFail(ctx, msg);
}
[Conditional("DEBUG")]
public static void AssertValue<T>(T val) where T : class
{
if (object.ReferenceEquals(val, null))
DbgFailValue();
}
[Conditional("DEBUG")]
public static void AssertValue<T>(this IExceptionContext ctx, T val) where T : class
{
if (object.ReferenceEquals(val, null))
DbgFailValue(ctx);
}
[Conditional("DEBUG")]
public static void AssertValue<T>(T val, string paramName) where T : class
{
if (object.ReferenceEquals(val, null))
DbgFailValue(paramName);
}
[Conditional("DEBUG")]
public static void AssertValue<T>(this IExceptionContext ctx, T val, string paramName) where T : class
{
if (object.ReferenceEquals(val, null))
DbgFailValue(ctx, paramName);
}
[Conditional("DEBUG")]
public static void AssertValue<T>(T val, string name, string msg) where T : class
{
if (object.ReferenceEquals(val, null))
DbgFailValue(name, msg);
}
[Conditional("DEBUG")]
public static void AssertValue<T>(this IExceptionContext ctx, T val, string name, string msg) where T : class
{
if (object.ReferenceEquals(val, null))
DbgFailValue(ctx, name, msg);
}
[Conditional("DEBUG")]
public static void AssertNonEmpty(string s)
{
if (string.IsNullOrEmpty(s))
DbgFailEmpty();
}
[Conditional("DEBUG")]
public static void AssertNonEmpty(this IExceptionContext ctx, string s)
{
if (string.IsNullOrEmpty(s))
DbgFailEmpty(ctx);
}
[Conditional("DEBUG")]
public static void AssertNonWhiteSpace(string s)
{
if (string.IsNullOrWhiteSpace(s))
DbgFailEmpty();
}
[Conditional("DEBUG")]
public static void AssertNonWhiteSpace(this IExceptionContext ctx, string s)
{
if (string.IsNullOrWhiteSpace(s))
DbgFailEmpty(ctx);
}
[Conditional("DEBUG")]
public static void AssertNonEmpty(string s, string msg)
{
if (string.IsNullOrEmpty(s))
DbgFailEmpty(msg);
}
[Conditional("DEBUG")]
public static void AssertNonEmpty(this IExceptionContext ctx, string s, string msg)
{
if (string.IsNullOrEmpty(s))
DbgFailEmpty(ctx, msg);
}
[Conditional("DEBUG")]
public static void AssertNonWhiteSpace(string s, string msg)
{
if (string.IsNullOrWhiteSpace(s))
DbgFailEmpty(msg);
}
[Conditional("DEBUG")]
public static void AssertNonWhiteSpace(this IExceptionContext ctx, string s, string msg)
{
if (string.IsNullOrWhiteSpace(s))
DbgFailEmpty(ctx, msg);
}
[Conditional("DEBUG")]
public static void AssertNonEmpty<T>(ReadOnlySpan<T> args)
{
if (args.IsEmpty)
DbgFail();
}
[Conditional("DEBUG")]
public static void AssertNonEmpty<T>(Span<T> args)
{
if (args.IsEmpty)
DbgFail();
}
[Conditional("DEBUG")]
public static void AssertNonEmpty<T>(ICollection<T> args)
{
if (Size(args) == 0)
DbgFail();
}
[Conditional("DEBUG")]
public static void AssertNonEmpty<T>(this IExceptionContext ctx, ICollection<T> args)
{
if (Size(args) == 0)
DbgFail(ctx);
}
[Conditional("DEBUG")]
public static void AssertNonEmpty<T>(ICollection<T> args, string msg)
{
if (Size(args) == 0)
DbgFail(msg);
}
[Conditional("DEBUG")]
public static void AssertNonEmpty<T>(this IExceptionContext ctx, ICollection<T> args, string msg)
{
if (Size(args) == 0)
DbgFail(ctx, msg);
}
/// <summary>
/// This documents that the parameter can legally be null.
/// </summary>
[Conditional("INVARIANT_CHECKS")]
public static void AssertValueOrNull<T>(T val) where T : class
{
}
[Conditional("INVARIANT_CHECKS")]
public static void AssertValueOrNull<T>(this IExceptionContext ctx, T val) where T : class
{
}
}