| | 1 | | namespace Songhay.Extensions; |
| | 2 | |
|
| | 3 | | /// <summary> |
| | 4 | | /// Extensions of <c>Nullable</c> types. |
| | 5 | | /// </summary> |
| | 6 | | public static class NullableExtensions |
| | 7 | | { |
| | 8 | | /// <summary> |
| | 9 | | /// Determines whether the specified type |
| | 10 | | /// can be assigned to <see cref="ISerializable" />. |
| | 11 | | /// </summary> |
| | 12 | | /// <typeparam name="T">the specified type</typeparam> |
| | 13 | | /// <param name="nullable">the nullable</param> |
| | 14 | | /// <returns> |
| | 15 | | /// <c>true</c> if the specified throw exception is serializable; otherwise, <c>false</c>. |
| | 16 | | /// </returns> |
| | 17 | | /// <remarks> |
| | 18 | | /// For detail, see https://stackoverflow.com/a/945528/22944. |
| | 19 | | /// For background, see https://manski.net/2014/10/net-serializers-comparison-chart/ |
| | 20 | | /// and https://github.com/BryanWilhite/SonghayCore/issues/76 |
| | 21 | | /// </remarks> |
| | 22 | | public static bool IsAssignableToISerializable<T>(this T? nullable) => |
| 2 | 23 | | typeof(ISerializable).IsAssignableFrom(typeof(T)); |
| | 24 | |
|
| | 25 | | /// <summary> |
| | 26 | | /// Rounds the specified decimal. |
| | 27 | | /// </summary> |
| | 28 | | /// <param name="nullable">The decimal nullable.</param> |
| | 29 | | /// <param name="decimals">The decimals.</param> |
| | 30 | | /// <remarks> |
| | 31 | | /// For more detail see http://anderly.com/2009/08/08/silverlight-midpoint-rounding-solution/ |
| | 32 | | /// </remarks> |
| | 33 | | public static decimal Round(this decimal? nullable, int decimals) |
| 0 | 34 | | { |
| 0 | 35 | | var d = nullable.GetValueOrDefault(); |
| 0 | 36 | | decimal factor = Convert.ToDecimal(Math.Pow(10, decimals)); |
| 0 | 37 | | int sign = Math.Sign(d); |
| | 38 | |
|
| 0 | 39 | | return Decimal.Truncate(d * factor + 0.5m * sign) / factor; |
| 0 | 40 | | } |
| | 41 | |
|
| | 42 | | /// <summary> |
| | 43 | | /// Throws an <see cref="ArgumentNullException"/> |
| | 44 | | /// when the specified enumerable is null or empty. |
| | 45 | | /// </summary> |
| | 46 | | /// <param name="enumerable">the <see cref="IEnumerable{T}"/></param> |
| | 47 | | /// <param name="paramName">the name of the variable holding the <see cref="IEnumerable{T}"/></param> |
| | 48 | | /// <typeparam name="T">the type of the <see cref="IEnumerable{T}"/></typeparam> |
| | 49 | | public static void ThrowWhenNullOrEmpty<T>( [NotNull] this IEnumerable<T>? enumerable, |
| | 50 | | [CallerArgumentExpression("enumerable")] string? paramName = null) |
| 11 | 51 | | { |
| 18 | 52 | | if (enumerable != null && enumerable.Any()) return; |
| | 53 | |
|
| 4 | 54 | | if (string.IsNullOrWhiteSpace(paramName)) |
| 0 | 55 | | paramName = $"[variable of type `{nameof(IEnumerable)}` of `{typeof(T).Name}`]"; |
| | 56 | |
|
| 4 | 57 | | throw new ArgumentNullException(paramName); |
| 7 | 58 | | } |
| | 59 | |
|
| | 60 | | /// <summary> |
| | 61 | | /// Throws an <see cref="ArgumentNullException"/> |
| | 62 | | /// when <see cref="string.IsNullOrWhiteSpace"/> is <c>true</c>. |
| | 63 | | /// </summary> |
| | 64 | | /// <param name="nullable">the nullable <see cref="string"/></param> |
| | 65 | | /// <param name="paramName">the name of the variable holding the <see cref="string"/></param> |
| | 66 | | /// <remarks> |
| | 67 | | /// This member borrows heavily from <see cref="ArgumentNullException.ThrowIfNull"/>. |
| | 68 | | /// |
| | 69 | | /// The <see cref="NotNullAttribute"/> is applied to this member based |
| | 70 | | /// on the following statement from Microsoft: |
| | 71 | | /// |
| | 72 | | /// “Callers can pass a variable with the null nullable, |
| | 73 | | /// but the argument is guaranteed to never be null |
| | 74 | | /// if the method returns without throwing an exception.” |
| | 75 | | /// |
| | 76 | | /// [ see https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/nullable-analysis#postconditi |
| | 77 | | /// </remarks> |
| | 78 | | public static void ThrowWhenNullOrWhiteSpace( [NotNull] this string? nullable, |
| | 79 | | [CallerArgumentExpression("nullable")] string? paramName = null) |
| 384 | 80 | | { |
| 766 | 81 | | if (!string.IsNullOrWhiteSpace(nullable)) return; |
| | 82 | |
|
| 2 | 83 | | if (string.IsNullOrWhiteSpace(paramName)) paramName = $"[variable of type `{nameof(String)}`]"; |
| | 84 | |
|
| 2 | 85 | | throw new ArgumentNullException(paramName); |
| 382 | 86 | | } |
| | 87 | |
|
| | 88 | | /// <summary> |
| | 89 | | /// Boxes the nullable in <see cref="object"/> |
| | 90 | | /// or returns <see cref="DBNull"/>. |
| | 91 | | /// </summary> |
| | 92 | | /// <param name="nullable">the nullable</param> |
| 0 | 93 | | public static object ToObjectOrDbNull<T>(this T? nullable) => nullable as object ?? DBNull.Value; |
| | 94 | |
|
| | 95 | | /// <summary> |
| | 96 | | /// Returns the non-null value of the specified, nullable reference type |
| | 97 | | /// or throws an <see cref="ArgumentNullException"/> |
| | 98 | | /// when the value is null. |
| | 99 | | /// </summary> |
| | 100 | | /// <param name="nullable">the nullable</param> |
| | 101 | | /// <param name="paramName">the name of the variable holding the nullable</param> |
| | 102 | | /// <typeparam name="T">the type</typeparam> |
| | 103 | | /// <remarks> |
| | 104 | | /// This member borrows heavily from <see cref="ArgumentNullException.ThrowIfNull"/>. |
| | 105 | | /// |
| | 106 | | /// The <see cref="NotNullAttribute"/> is applied to this member based |
| | 107 | | /// on the following statement from Microsoft: |
| | 108 | | /// |
| | 109 | | /// “Callers can pass a variable with the null nullable, |
| | 110 | | /// but the argument is guaranteed to never be null |
| | 111 | | /// if the method returns without throwing an exception.” |
| | 112 | | /// |
| | 113 | | /// [ see https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/nullable-analysis#postconditi |
| | 114 | | /// </remarks> |
| | 115 | | public static T ToReferenceTypeValueOrThrow<T>( [NotNull] this T? nullable, |
| | 116 | | [CallerArgumentExpression("nullable")] string? paramName = null) where T: class? |
| 54 | 117 | | { |
| 107 | 118 | | if (nullable != null) return nullable; |
| | 119 | |
|
| 1 | 120 | | if (string.IsNullOrWhiteSpace(paramName)) paramName = $"[variable of type `{typeof(T).Name}`]"; |
| | 121 | |
|
| 1 | 122 | | throw new ArgumentNullException(paramName); |
| 53 | 123 | | } |
| | 124 | |
|
| | 125 | | /// <summary> |
| | 126 | | /// Returns the non-null value of the specified value type |
| | 127 | | /// or throws an <see cref="ArgumentNullException"/> |
| | 128 | | /// when the value is null. |
| | 129 | | /// </summary> |
| | 130 | | /// <param name="nullable">the nullable</param> |
| | 131 | | /// <param name="paramName">the name of the variable holding the nullable</param> |
| | 132 | | /// <typeparam name="T">the type</typeparam> |
| | 133 | | /// <remarks> |
| | 134 | | /// This member borrows heavily from <see cref="ArgumentNullException.ThrowIfNull"/>. |
| | 135 | | /// |
| | 136 | | /// The <see cref="NotNullAttribute"/> is applied to this member based |
| | 137 | | /// on the following statement from Microsoft: |
| | 138 | | /// |
| | 139 | | /// “Callers can pass a variable with the null nullable, |
| | 140 | | /// but the argument is guaranteed to never be null |
| | 141 | | /// if the method returns without throwing an exception.” |
| | 142 | | /// |
| | 143 | | /// [ see https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/nullable-analysis#postconditi |
| | 144 | | /// </remarks> |
| | 145 | | public static T ToValueOrThrow<T>( [NotNull] this T? nullable, |
| | 146 | | [CallerArgumentExpression("nullable")] string? paramName = null) where T: struct |
| 5 | 147 | | { |
| 9 | 148 | | if (nullable.HasValue) return nullable.Value; |
| | 149 | |
|
| 1 | 150 | | if (string.IsNullOrWhiteSpace(paramName)) paramName = $"[variable of type `{typeof(T).Name}`]"; |
| | 151 | |
|
| 1 | 152 | | throw new ArgumentNullException(paramName); |
| 4 | 153 | | } |
| | 154 | | } |