Fix extension methods

This commit is contained in:
Nikolaj Geisle
2022-01-11 11:47:31 +01:00
parent 32b1225291
commit 521023372b
18 changed files with 255 additions and 220 deletions

View File

@@ -17,9 +17,9 @@ namespace Umbraco.Cms.Core
/// <typeparam name="TResult">The type of the attempted operation result.</typeparam>
/// <param name="result">The result of the attempt.</param>
/// <returns>The successful attempt.</returns>
public static Attempt<TResult> Succeed<TResult>(TResult result)
public static Attempt<TResult?> Succeed<TResult>(TResult? result)
{
return Attempt<TResult>.Succeed(result);
return Attempt<TResult?>.Succeed(result);
}
/// <summary>

View File

@@ -10,7 +10,7 @@ namespace Umbraco.Cms.Core
public struct Attempt<TResult>
{
// private - use Succeed() or Fail() methods to create attempts
private Attempt(bool success, TResult result, Exception exception)
private Attempt(bool? success, TResult? result, Exception? exception)
{
Success = success;
Result = result;
@@ -20,22 +20,22 @@ namespace Umbraco.Cms.Core
/// <summary>
/// Gets a value indicating whether this <see cref="Attempt{TResult}"/> was successful.
/// </summary>
public bool Success { get; }
public bool? Success { get; }
/// <summary>
/// Gets the exception associated with an unsuccessful attempt.
/// </summary>
public Exception Exception { get; }
public Exception? Exception { get; }
/// <summary>
/// Gets the attempt result.
/// </summary>
public TResult Result { get; }
public TResult? Result { get; }
/// <summary>
/// Gets the attempt result, if successful, else a default value.
/// </summary>
public TResult ResultOr(TResult value) => Success ? Result : value;
public TResult? ResultOr(TResult? value) => Success.HasValue && Success.Value ? Result : value;
// optimize, use a singleton failed attempt
private static readonly Attempt<TResult> Failed = new Attempt<TResult>(false, default(TResult), null);
@@ -54,7 +54,7 @@ namespace Umbraco.Cms.Core
/// </summary>
/// <param name="result">The result of the attempt.</param>
/// <returns>The successful attempt.</returns>
public static Attempt<TResult> Succeed(TResult result)
public static Attempt<TResult> Succeed(TResult? result)
{
return new Attempt<TResult>(true, result, null);
}
@@ -73,7 +73,7 @@ namespace Umbraco.Cms.Core
/// </summary>
/// <param name="exception">The exception causing the failure of the attempt.</param>
/// <returns>The failed attempt.</returns>
public static Attempt<TResult> Fail(Exception exception)
public static Attempt<TResult> Fail(Exception? exception)
{
return new Attempt<TResult>(false, default(TResult), exception);
}
@@ -115,7 +115,7 @@ namespace Umbraco.Cms.Core
/// <param name="condition">A value indicating whether the attempt is successful.</param>
/// <param name="result">The result of the attempt.</param>
/// <returns>The attempt.</returns>
public static Attempt<TResult> If(bool condition, TResult result)
public static Attempt<TResult> If(bool condition, TResult? result)
{
return new Attempt<TResult>(condition, result, null);
}
@@ -125,7 +125,7 @@ namespace Umbraco.Cms.Core
/// </summary>
/// <param name="a"></param>
/// <returns></returns>
public static implicit operator bool(Attempt<TResult> a)
public static implicit operator bool?(Attempt<TResult> a)
{
return a.Success;
}

View File

@@ -23,8 +23,7 @@ namespace Umbraco.Extensions
{
return _rootDir;
}
var codeBase = executingAssembly.CodeBase;
var codeBase = executingAssembly.Location;
var uri = new Uri(codeBase);
var path = uri.LocalPath;
var baseDirectory = Path.GetDirectoryName(path);
@@ -45,7 +44,7 @@ namespace Umbraco.Extensions
/// <returns></returns>
public static FileInfo GetAssemblyFile(this Assembly assembly)
{
var codeBase = assembly.CodeBase;
var codeBase = assembly.Location;
var uri = new Uri(codeBase);
var path = uri.LocalPath;
return new FileInfo(path);
@@ -58,7 +57,7 @@ namespace Umbraco.Extensions
/// <returns></returns>
public static bool IsAppCodeAssembly(this Assembly assembly)
{
if (assembly.FullName.StartsWith("App_Code"))
if (assembly.FullName!.StartsWith("App_Code"))
{
try
{
@@ -82,7 +81,7 @@ namespace Umbraco.Extensions
public static bool IsGlobalAsaxAssembly(this Assembly assembly)
{
//only way I can figure out how to test is by the name
return assembly.FullName.StartsWith("App_global.asax");
return assembly.FullName!.StartsWith("App_global.asax");
}
/// <summary>
@@ -90,12 +89,17 @@ namespace Umbraco.Extensions
/// </summary>
/// <param name="assemblyName"></param>
/// <returns></returns>
public static FileInfo GetAssemblyFile(this AssemblyName assemblyName)
public static FileInfo? GetAssemblyFile(this AssemblyName assemblyName)
{
var codeBase = assemblyName.CodeBase;
var uri = new Uri(codeBase);
var path = uri.LocalPath;
return new FileInfo(path);
if (!string.IsNullOrEmpty(codeBase))
{
var uri = new Uri(codeBase);
var path = uri.LocalPath;
return new FileInfo(path);
}
return null;
}
}

View File

@@ -13,7 +13,7 @@ namespace Umbraco.Extensions
{
public static class ClaimsIdentityExtensions
{
public static T GetUserId<T>(this IIdentity identity)
public static T? GetUserId<T>(this IIdentity identity)
{
var strId = identity.GetUserId();
var converted = strId.TryConvertTo<T>();
@@ -27,11 +27,11 @@ namespace Umbraco.Extensions
/// <returns>
/// The string value of the user id if found otherwise null
/// </returns>
public static string GetUserId(this IIdentity identity)
public static string? GetUserId(this IIdentity identity)
{
if (identity == null) throw new ArgumentNullException(nameof(identity));
string userId = null;
string? userId = null;
if (identity is ClaimsIdentity claimsIdentity)
{
userId = claimsIdentity.FindFirstValue(ClaimTypes.NameIdentifier)
@@ -48,11 +48,11 @@ namespace Umbraco.Extensions
/// <returns>
/// The string value of the user name if found otherwise null
/// </returns>
public static string GetUserName(this IIdentity identity)
public static string? GetUserName(this IIdentity identity)
{
if (identity == null) throw new ArgumentNullException(nameof(identity));
string username = null;
string? username = null;
if (identity is ClaimsIdentity claimsIdentity)
{
username = claimsIdentity.FindFirstValue(ClaimTypes.Name)
@@ -70,7 +70,7 @@ namespace Umbraco.Extensions
/// <returns>
/// The string value of the claim if found otherwise null
/// </returns>
public static string FindFirstValue(this ClaimsIdentity identity, string claimType)
public static string? FindFirstValue(this ClaimsIdentity identity, string claimType)
{
if (identity == null) throw new ArgumentNullException(nameof(identity));
@@ -100,7 +100,7 @@ namespace Umbraco.Extensions
/// <param name="identity"></param>
/// <param name="verifiedIdentity">Verified identity wrapped in a ClaimsIdentity with BackOfficeAuthentication type</param>
/// <returns>True if ClaimsIdentity</returns>
public static bool VerifyBackOfficeIdentity(this ClaimsIdentity identity, out ClaimsIdentity verifiedIdentity)
public static bool VerifyBackOfficeIdentity(this ClaimsIdentity identity, out ClaimsIdentity? verifiedIdentity)
{
if (identity is null)
{
@@ -119,7 +119,7 @@ namespace Umbraco.Extensions
}
}
verifiedIdentity = identity.AuthenticationType == Constants.Security.BackOfficeAuthenticationType ? identity : new ClaimsIdentity(identity.Claims, Constants.Security.BackOfficeAuthenticationType);
verifiedIdentity = identity.AuthenticationType == Constants.Security.BackOfficeAuthenticationType ? identity : new ClaimsIdentity(identity.Claims, Constants.Security.BackOfficeAuthenticationType);
return true;
}
@@ -294,35 +294,44 @@ namespace Umbraco.Extensions
/// </summary>
/// <param name="identity"></param>
/// <returns>User ID as integer</returns>
public static int GetId(this ClaimsIdentity identity) => int.Parse(identity.FindFirstValue(ClaimTypes.NameIdentifier), CultureInfo.InvariantCulture);
public static int? GetId(this ClaimsIdentity identity)
{
var firstValue = identity.FindFirstValue(ClaimTypes.NameIdentifier);
if (firstValue is not null)
{
int.Parse(firstValue, CultureInfo.InvariantCulture);
}
return null;
}
/// <summary>
/// Get the real name belonging to the user from a ClaimsIdentity
/// </summary>
/// <param name="identity"></param>
/// <returns>Real name of the user</returns>
public static string GetRealName(this ClaimsIdentity identity) => identity.FindFirstValue(ClaimTypes.GivenName);
public static string? GetRealName(this ClaimsIdentity identity) => identity.FindFirstValue(ClaimTypes.GivenName);
/// <summary>
/// Get the username of the user from a ClaimsIdentity
/// </summary>
/// <param name="identity"></param>
/// <returns>Username of the user</returns>
public static string GetUsername(this ClaimsIdentity identity) => identity.FindFirstValue(ClaimTypes.Name);
public static string? GetUsername(this ClaimsIdentity identity) => identity.FindFirstValue(ClaimTypes.Name);
/// <summary>
/// Get the culture string from a ClaimsIdentity
/// </summary>
/// <param name="identity"></param>
/// <returns>Culture string</returns>
public static string GetCultureString(this ClaimsIdentity identity) => identity.FindFirstValue(ClaimTypes.Locality);
public static string? GetCultureString(this ClaimsIdentity identity) => identity.FindFirstValue(ClaimTypes.Locality);
/// <summary>
/// Get the security stamp from a ClaimsIdentity
/// </summary>
/// <param name="identity"></param>
/// <returns>Security stamp</returns>
public static string GetSecurityStamp(this ClaimsIdentity identity) => identity.FindFirstValue(Constants.Security.SecurityStampClaimType);
public static string? GetSecurityStamp(this ClaimsIdentity identity) => identity.FindFirstValue(Constants.Security.SecurityStampClaimType);
/// <summary>
/// Get the roles assigned to a user from a ClaimsIdentity
@@ -336,17 +345,20 @@ namespace Umbraco.Extensions
/// <summary>
/// Adds or updates and existing claim.
/// </summary>
public static void AddOrUpdateClaim(this ClaimsIdentity identity, Claim claim)
public static void AddOrUpdateClaim(this ClaimsIdentity identity, Claim? claim)
{
if (identity == null)
{
throw new ArgumentNullException(nameof(identity));
}
Claim existingClaim = identity.Claims.FirstOrDefault(x => x.Type == claim.Type);
identity.TryRemoveClaim(existingClaim);
if (claim is not null)
{
Claim? existingClaim = identity.Claims.FirstOrDefault(x => x.Type == claim.Type);
identity.TryRemoveClaim(existingClaim);
identity.AddClaim(claim);
identity.AddClaim(claim);
}
}
}
}

View File

@@ -289,10 +289,10 @@ namespace Umbraco.Extensions
/// <para>Basically, exact is for one content type, or one property type, and !exact is for "all property types" of one content type.</para>
/// <para>Both <paramref name="culture" /> and <paramref name="segment" /> can be "*" to indicate "all of them".</para>
/// </remarks>
public static bool ValidateVariation(this ContentVariation variation, string culture, string segment, bool exact, bool wildcards, bool throwIfInvalid)
public static bool ValidateVariation(this ContentVariation variation, string? culture, string? segment, bool exact, bool wildcards, bool throwIfInvalid)
{
culture = culture.NullOrWhiteSpaceAsNull();
segment = segment.NullOrWhiteSpaceAsNull();
culture = culture?.NullOrWhiteSpaceAsNull();
segment = segment?.NullOrWhiteSpaceAsNull();
// if wildcards are disabled, do not allow "*"
if (!wildcards && (culture == "*" || segment == "*"))

View File

@@ -10,7 +10,7 @@ namespace Umbraco.Extensions
{
public static class DelegateExtensions
{
public static Attempt<T> RetryUntilSuccessOrTimeout<T>(this Func<Attempt<T>> task, TimeSpan timeout, TimeSpan pause)
public static Attempt<T?> RetryUntilSuccessOrTimeout<T>(this Func<Attempt<T?>> task, TimeSpan timeout, TimeSpan pause)
{
if (pause.TotalMilliseconds < 0)
{
@@ -20,14 +20,14 @@ namespace Umbraco.Extensions
do
{
var result = task();
if (result) { return result; }
if (result.Success.HasValue && result.Success.Value) { return result; }
Thread.Sleep((int)pause.TotalMilliseconds);
}
while (stopwatch.Elapsed < timeout);
return Attempt<T>.Fail();
return Attempt<T?>.Fail();
}
public static Attempt<T> RetryUntilSuccessOrMaxAttempts<T>(this Func<int, Attempt<T>> task, int totalAttempts, TimeSpan pause)
public static Attempt<T?> RetryUntilSuccessOrMaxAttempts<T>(this Func<int, Attempt<T?>> task, int totalAttempts, TimeSpan pause)
{
if (pause.TotalMilliseconds < 0)
{
@@ -38,11 +38,11 @@ namespace Umbraco.Extensions
{
attempts++;
var result = task(attempts);
if (result) { return result; }
if (result.Success.HasValue && result.Success.Value) { return result; }
Thread.Sleep((int)pause.TotalMilliseconds);
}
while (attempts < totalAttempts);
return Attempt<T>.Fail();
return Attempt<T?>.Fail();
}
}
}

View File

@@ -53,8 +53,9 @@ namespace Umbraco.Extensions
/// If there is an item in the dictionary with the key, it will keep trying to update it until it can
/// </remarks>
public static bool TryUpdate<TKey, TValue>(this ConcurrentDictionary<TKey, TValue> dict, TKey key, Func<TValue, TValue> updateFactory)
where TKey : notnull
{
TValue curValue;
TValue? curValue;
while (dict.TryGetValue(key, out curValue))
{
if (dict.TryUpdate(key, updateFactory(curValue), curValue))
@@ -80,8 +81,9 @@ namespace Umbraco.Extensions
/// WARNING: If the value changes after we've retrieved it, then the item will not be updated
/// </remarks>
public static bool TryUpdateOptimisitic<TKey, TValue>(this ConcurrentDictionary<TKey, TValue> dict, TKey key, Func<TValue, TValue> updateFactory)
where TKey : notnull
{
TValue curValue;
TValue? curValue;
if (!dict.TryGetValue(key, out curValue))
return false;
dict.TryUpdate(key, updateFactory(curValue), curValue);
@@ -96,11 +98,12 @@ namespace Umbraco.Extensions
/// <param name="d"></param>
/// <returns></returns>
public static IDictionary<TKeyOut, TValOut> ConvertTo<TKeyOut, TValOut>(this IDictionary d)
where TKeyOut : notnull
{
var result = new Dictionary<TKeyOut, TValOut>();
foreach (DictionaryEntry v in d)
{
result.Add((TKeyOut)v.Key, (TValOut)v.Value);
result.Add((TKeyOut)v.Key, (TValOut)v.Value!);
}
return result;
}
@@ -115,11 +118,12 @@ namespace Umbraco.Extensions
/// <param name="valConverter"></param>
/// <returns></returns>
public static IDictionary<TKeyOut, TValOut> ConvertTo<TKeyOut, TValOut>(this IDictionary d, Func<object, TKeyOut> keyConverter, Func<object, TValOut> valConverter)
where TKeyOut : notnull
{
var result = new Dictionary<TKeyOut, TValOut>();
foreach (DictionaryEntry v in d)
{
result.Add(keyConverter(v.Key), valConverter(v.Value));
result.Add(keyConverter(v.Key), valConverter(v.Value!));
}
return result;
}
@@ -205,7 +209,7 @@ namespace Umbraco.Extensions
/// <param name="d"></param>
/// <param name="key"></param>
/// <returns></returns>
public static string GetValueAsString<TKey, TVal>(this IDictionary<TKey, TVal> d, TKey key)
public static string? GetValueAsString<TKey, TVal>(this IDictionary<TKey, TVal> d, TKey key)
=> d.ContainsKey(key) ? d[key]!.ToString() : string.Empty;
/// <summary>
@@ -215,7 +219,7 @@ namespace Umbraco.Extensions
/// <param name="key"></param>
/// <param name="defaultValue"></param>
/// <returns></returns>
public static string GetValueAsString<TKey, TVal>(this IDictionary<TKey, TVal> d, TKey key, string defaultValue)
public static string? GetValueAsString<TKey, TVal>(this IDictionary<TKey, TVal> d, TKey key, string defaultValue)
{
if (d.ContainsKey(key))
{
@@ -269,12 +273,13 @@ namespace Umbraco.Extensions
/// <param name="defaultValue">The default value.</param>
/// <typeparam name="TValue">The type</typeparam>
/// <returns>The entry</returns>
public static TValue GetValueIgnoreCase<TValue>(this IDictionary<string, TValue> dictionary, string key, TValue defaultValue)
public static TValue GetValueIgnoreCase<TValue>(this IDictionary<string, TValue> dictionary, string? key, TValue
defaultValue)
{
key = dictionary.Keys.FirstOrDefault(i => i.InvariantEquals(key));
return key.IsNullOrWhiteSpace() == false
? dictionary[key]
? dictionary[key!]
: defaultValue;
}
@@ -282,6 +287,7 @@ namespace Umbraco.Extensions
this IEnumerable<TInput> enumerable,
Func<TInput, TKey> syncKeySelector,
Func<TInput, Task<TValue>> asyncValueSelector)
where TKey : notnull
{
Dictionary<TKey,TValue> dictionary = new Dictionary<TKey, TValue>();

View File

@@ -39,7 +39,7 @@ namespace Umbraco.Extensions
yield return item;
}
public static IEnumerable<IEnumerable<T>> InGroupsOf<T>(this IEnumerable<T> source, int groupSize)
public static IEnumerable<IEnumerable<T>> InGroupsOf<T>(this IEnumerable<T>? source, int groupSize)
{
if (source == null)
throw new ArgumentNullException("source");
@@ -49,7 +49,7 @@ namespace Umbraco.Extensions
// following code derived from MoreLinq and does not allocate bazillions of tuples
T[] temp = null;
T[]? temp = null;
var count = 0;
foreach (var item in source)
@@ -234,9 +234,8 @@ namespace Umbraco.Extensions
return sequence.Select(
x =>
{
if (x is TActual)
if (x is TActual casted)
{
var casted = x as TActual;
projection.Invoke(casted);
}
return x;
@@ -342,7 +341,7 @@ namespace Umbraco.Extensions
// this is to support filtering with multiple types
public static IEnumerable<T> OfTypes<T>(this IEnumerable<T> contents, params Type[] types)
{
return contents.Where(x => types.Contains(x.GetType()));
return contents.Where(x => types.Contains(x?.GetType()));
}
public static IEnumerable<T> SkipLast<T>(this IEnumerable<T> source)

View File

@@ -9,11 +9,11 @@ namespace Umbraco.Extensions
{
public static class NameValueCollectionExtensions
{
public static IEnumerable<KeyValuePair<string, string>> AsEnumerable(this NameValueCollection nvc)
public static IEnumerable<KeyValuePair<string?, string?>> AsEnumerable(this NameValueCollection nvc)
{
foreach (string key in nvc.AllKeys)
foreach (string? key in nvc.AllKeys)
{
yield return new KeyValuePair<string, string>(key, nvc[key]);
yield return new KeyValuePair<string?, string?>(key, nvc[key]);
}
}
@@ -22,7 +22,7 @@ namespace Umbraco.Extensions
return collection.Keys.Cast<object>().Any(k => (string) k == key);
}
public static T GetValue<T>(this NameValueCollection collection, string key, T defaultIfNotFound)
public static T? GetValue<T>(this NameValueCollection collection, string key, T defaultIfNotFound)
{
if (collection.ContainsKey(key) == false)
{
@@ -37,7 +37,7 @@ namespace Umbraco.Extensions
var result = val.TryConvertTo<T>();
return result.Success ? result.Result : defaultIfNotFound;
return result.Success.HasValue && result.Success.Value ? result.Result : defaultIfNotFound;
}
}
}

View File

@@ -22,9 +22,9 @@ namespace Umbraco.Extensions
/// </summary>
public static class ObjectExtensions
{
private static readonly ConcurrentDictionary<Type, Type> NullableGenericCache = new ConcurrentDictionary<Type, Type>();
private static readonly ConcurrentDictionary<CompositeTypeTypeKey, TypeConverter> InputTypeConverterCache = new ConcurrentDictionary<CompositeTypeTypeKey, TypeConverter>();
private static readonly ConcurrentDictionary<CompositeTypeTypeKey, TypeConverter> DestinationTypeConverterCache = new ConcurrentDictionary<CompositeTypeTypeKey, TypeConverter>();
private static readonly ConcurrentDictionary<Type, Type?> NullableGenericCache = new ConcurrentDictionary<Type, Type?>();
private static readonly ConcurrentDictionary<CompositeTypeTypeKey, TypeConverter?> InputTypeConverterCache = new ConcurrentDictionary<CompositeTypeTypeKey, TypeConverter?>();
private static readonly ConcurrentDictionary<CompositeTypeTypeKey, TypeConverter?> DestinationTypeConverterCache = new ConcurrentDictionary<CompositeTypeTypeKey, TypeConverter?>();
private static readonly ConcurrentDictionary<CompositeTypeTypeKey, bool> AssignableTypeCache = new ConcurrentDictionary<CompositeTypeTypeKey, bool>();
private static readonly ConcurrentDictionary<Type, bool> BoolConvertCache = new ConcurrentDictionary<Type, bool>();
@@ -61,7 +61,7 @@ namespace Umbraco.Extensions
/// <typeparam name="T"></typeparam>
/// <param name="input">The input.</param>
/// <returns></returns>
public static T SafeCast<T>(this object input)
public static T? SafeCast<T>(this object input)
{
if (ReferenceEquals(null, input) || ReferenceEquals(default(T), input)) return default;
if (input is T variable) return variable;
@@ -77,11 +77,11 @@ namespace Umbraco.Extensions
/// <returns>The <see cref="Attempt{T}"/></returns>
public static Attempt<T> TryConvertTo<T>(this object? input)
{
Attempt<object> result = TryConvertTo(input, typeof(T));
Attempt<object?> result = TryConvertTo(input, typeof(T));
if (result.Success)
if (result.Success.HasValue && result.Success.Value)
{
return Attempt<T>.Succeed((T)result.Result);
return Attempt<T>.Succeed((T?)result.Result);
}
if (input == null)
@@ -94,7 +94,7 @@ namespace Umbraco.Extensions
else
{
// sure, null can be any object
return Attempt<T>.Succeed((T)input);
return Attempt<T>.Succeed((T)input!);
}
}
@@ -116,11 +116,11 @@ namespace Umbraco.Extensions
/// <param name="input">The input.</param>
/// <param name="target">The type to convert to</param>
/// <returns>The <see cref="Attempt{Object}"/></returns>
public static Attempt<object> TryConvertTo(this object input, Type target)
public static Attempt<object?> TryConvertTo(this object? input, Type target)
{
if (target == null)
{
return Attempt<object>.Fail();
return Attempt<object?>.Fail();
}
try
@@ -130,11 +130,11 @@ namespace Umbraco.Extensions
// Nullable is ok
if (target.IsGenericType && GetCachedGenericNullableType(target) != null)
{
return Attempt<object>.Succeed(null);
return Attempt<object?>.Succeed(null);
}
// Reference types are ok
return Attempt<object>.If(target.IsValueType == false, null);
return Attempt<object?>.If(target.IsValueType == false, null);
}
var inputType = input.GetType();
@@ -148,7 +148,7 @@ namespace Umbraco.Extensions
// Check for string so that overloaders of ToString() can take advantage of the conversion.
if (target == typeof(string))
{
return Attempt<object>.Succeed(input.ToString());
return Attempt<object?>.Succeed(input.ToString());
}
// If we've got a nullable of something, we try to convert directly to that thing.
@@ -165,7 +165,7 @@ namespace Umbraco.Extensions
// TODO: Why the check against only bool/date when a string is null/empty? In what scenario can we convert to another type when the string is null or empty other than just being null?
if (string.IsNullOrEmpty(inputString) && (underlying == typeof(DateTime) || underlying == typeof(bool)))
{
return Attempt<object>.Succeed(null);
return Attempt<object?>.Succeed(null);
}
}
@@ -173,13 +173,13 @@ namespace Umbraco.Extensions
var inner = input.TryConvertTo(underlying);
// And if successful, fall on through to rewrap in a nullable; if failed, pass on the exception
if (inner.Success)
if (inner.Success.HasValue && inner.Success.Value)
{
input = inner.Result; // Now fall on through...
}
else
{
return Attempt<object>.Fail(inner.Exception);
return Attempt<object?>.Fail(inner.Exception);
}
}
}
@@ -211,7 +211,7 @@ namespace Umbraco.Extensions
{
if (GetCachedCanConvertToBoolean(inputType))
{
return Attempt.Succeed(CustomBooleanTypeConverter.ConvertFrom(input));
return Attempt.Succeed(CustomBooleanTypeConverter.ConvertFrom(input!));
}
}
@@ -224,7 +224,7 @@ namespace Umbraco.Extensions
var outputConverter = GetCachedTargetTypeConverter(inputType, target);
if (outputConverter != null)
{
return Attempt.Succeed(outputConverter.ConvertFrom(input));
return Attempt.Succeed(outputConverter.ConvertFrom(input!));
}
if (target.IsGenericType && GetCachedGenericNullableType(target) != null)
@@ -243,10 +243,10 @@ namespace Umbraco.Extensions
}
catch (Exception e)
{
return Attempt<object>.Fail(e);
return Attempt<object?>.Fail(e);
}
return Attempt<object>.Fail();
return Attempt<object?>.Fail();
}
/// <summary>
@@ -256,12 +256,12 @@ namespace Umbraco.Extensions
/// <param name="input">The input.</param>
/// <param name="target">The type to convert to</param>
/// <returns>The <see cref="Nullable{Attempt}"/></returns>
private static Attempt<object>? TryConvertToFromString(this string input, Type target)
private static Attempt<object?>? TryConvertToFromString(this string input, Type target)
{
// Easy
if (target == typeof(string))
{
return Attempt<object>.Succeed(input);
return Attempt<object?>.Succeed(input);
}
// Null, empty, whitespaces
@@ -270,13 +270,13 @@ namespace Umbraco.Extensions
if (target == typeof(bool))
{
// null/empty = bool false
return Attempt<object>.Succeed(false);
return Attempt<object?>.Succeed(false);
}
if (target == typeof(DateTime))
{
// null/empty = min DateTime value
return Attempt<object>.Succeed(DateTime.MinValue);
return Attempt<object?>.Succeed(DateTime.MinValue);
}
// Cannot decide here,
@@ -296,25 +296,25 @@ namespace Umbraco.Extensions
{
if (int.TryParse(input, out var value))
{
return Attempt<object>.Succeed(value);
return Attempt<object?>.Succeed(value);
}
// Because decimal 100.01m will happily convert to integer 100, it
// makes sense that string "100.01" *also* converts to integer 100.
var input2 = NormalizeNumberDecimalSeparator(input);
return Attempt<object>.If(decimal.TryParse(input2, out var value2), Convert.ToInt32(value2));
return Attempt<object?>.If(decimal.TryParse(input2, out var value2), Convert.ToInt32(value2));
}
if (target == typeof(long))
{
if (long.TryParse(input, out var value))
{
return Attempt<object>.Succeed(value);
return Attempt<object?>.Succeed(value);
}
// Same as int
var input2 = NormalizeNumberDecimalSeparator(input);
return Attempt<object>.If(decimal.TryParse(input2, out var value2), Convert.ToInt64(value2));
return Attempt<object?>.If(decimal.TryParse(input2, out var value2), Convert.ToInt64(value2));
}
// TODO: Should we do the decimal trick for short, byte, unsigned?
@@ -323,7 +323,7 @@ namespace Umbraco.Extensions
{
if (bool.TryParse(input, out var value))
{
return Attempt<object>.Succeed(value);
return Attempt<object?>.Succeed(value);
}
// Don't declare failure so the CustomBooleanTypeConverter can try
@@ -334,38 +334,38 @@ namespace Umbraco.Extensions
switch (Type.GetTypeCode(target))
{
case TypeCode.Int16:
return Attempt<object>.If(short.TryParse(input, out var value), value);
return Attempt<object?>.If(short.TryParse(input, out var value), value);
case TypeCode.Double:
var input2 = NormalizeNumberDecimalSeparator(input);
return Attempt<object>.If(double.TryParse(input2, out var valueD), valueD);
return Attempt<object?>.If(double.TryParse(input2, out var valueD), valueD);
case TypeCode.Single:
var input3 = NormalizeNumberDecimalSeparator(input);
return Attempt<object>.If(float.TryParse(input3, out var valueF), valueF);
return Attempt<object?>.If(float.TryParse(input3, out var valueF), valueF);
case TypeCode.Char:
return Attempt<object>.If(char.TryParse(input, out var valueC), valueC);
return Attempt<object?>.If(char.TryParse(input, out var valueC), valueC);
case TypeCode.Byte:
return Attempt<object>.If(byte.TryParse(input, out var valueB), valueB);
return Attempt<object?>.If(byte.TryParse(input, out var valueB), valueB);
case TypeCode.SByte:
return Attempt<object>.If(sbyte.TryParse(input, out var valueSb), valueSb);
return Attempt<object?>.If(sbyte.TryParse(input, out var valueSb), valueSb);
case TypeCode.UInt32:
return Attempt<object>.If(uint.TryParse(input, out var valueU), valueU);
return Attempt<object?>.If(uint.TryParse(input, out var valueU), valueU);
case TypeCode.UInt16:
return Attempt<object>.If(ushort.TryParse(input, out var valueUs), valueUs);
return Attempt<object?>.If(ushort.TryParse(input, out var valueUs), valueUs);
case TypeCode.UInt64:
return Attempt<object>.If(ulong.TryParse(input, out var valueUl), valueUl);
return Attempt<object?>.If(ulong.TryParse(input, out var valueUl), valueUl);
}
}
else if (target == typeof(Guid))
{
return Attempt<object>.If(Guid.TryParse(input, out var value), value);
return Attempt<object?>.If(Guid.TryParse(input, out var value), value);
}
else if (target == typeof(DateTime))
{
@@ -375,34 +375,34 @@ namespace Umbraco.Extensions
{
case DateTimeKind.Unspecified:
case DateTimeKind.Utc:
return Attempt<object>.Succeed(value);
return Attempt<object?>.Succeed(value);
case DateTimeKind.Local:
return Attempt<object>.Succeed(value.ToUniversalTime());
return Attempt<object?>.Succeed(value.ToUniversalTime());
default:
throw new ArgumentOutOfRangeException();
}
}
return Attempt<object>.Fail();
return Attempt<object?>.Fail();
}
else if (target == typeof(DateTimeOffset))
{
return Attempt<object>.If(DateTimeOffset.TryParse(input, out var value), value);
return Attempt<object?>.If(DateTimeOffset.TryParse(input, out var value), value);
}
else if (target == typeof(TimeSpan))
{
return Attempt<object>.If(TimeSpan.TryParse(input, out var value), value);
return Attempt<object?>.If(TimeSpan.TryParse(input, out var value), value);
}
else if (target == typeof(decimal))
{
var input2 = NormalizeNumberDecimalSeparator(input);
return Attempt<object>.If(decimal.TryParse(input2, out var value), value);
return Attempt<object?>.If(decimal.TryParse(input2, out var value), value);
}
else if (input != null && target == typeof(Version))
{
return Attempt<object>.If(Version.TryParse(input, out var value), value);
return Attempt<object?>.If(Version.TryParse(input, out var value), value);
}
// E_NOTIMPL IPAddress, BigInteger
@@ -489,9 +489,9 @@ namespace Umbraco.Extensions
/// <param name="o"></param>
/// <param name="ignoreProperties"></param>
/// <returns></returns>
public static IDictionary<string, TVal> ToDictionary<T, TProperty, TVal>(this T o, params Expression<Func<T, TProperty>>[] ignoreProperties)
public static IDictionary<string, TVal>? ToDictionary<T, TProperty, TVal>(this T o, params Expression<Func<T, TProperty>>[] ignoreProperties)
{
return o.ToDictionary<TVal>(ignoreProperties.Select(e => o.GetPropertyInfo(e)).Select(propInfo => propInfo.Name).ToArray());
return o?.ToDictionary<TVal>(ignoreProperties.Select(e => o.GetPropertyInfo(e)).Select(propInfo => propInfo.Name).ToArray());
}
/// <summary>
@@ -521,7 +521,7 @@ namespace Umbraco.Extensions
internal static string ToDebugString(this object obj, int levels = 0)
internal static string? ToDebugString(this object? obj, int levels = 0)
{
if (obj == null) return "{null}";
try
@@ -589,7 +589,7 @@ namespace Umbraco.Extensions
/// <param name="value"></param>
/// <param name="type"></param>
/// <returns></returns>
internal static Attempt<string> TryConvertToXmlString(this object value, Type type)
internal static Attempt<string?> TryConvertToXmlString(this object value, Type type)
{
try
{
@@ -598,7 +598,7 @@ namespace Umbraco.Extensions
}
catch (NotSupportedException ex)
{
return Attempt<string>.Fail(ex);
return Attempt<string?>.Fail(ex);
}
}
@@ -608,7 +608,7 @@ namespace Umbraco.Extensions
/// <param name="value"></param>
/// <param name="type">The Type can only be a primitive type or Guid and byte[] otherwise an exception is thrown</param>
/// <returns></returns>
public static string ToXmlString(this object value, Type type)
public static string? ToXmlString(this object value, Type type)
{
if (value == null) return string.Empty;
if (type == typeof(string)) return (value.ToString().IsNullOrWhiteSpace() ? "" : value.ToString());
@@ -640,12 +640,12 @@ namespace Umbraco.Extensions
/// <typeparam name="T"></typeparam>
/// <param name="value"></param>
/// <returns></returns>
public static string ToXmlString<T>(this object value)
public static string? ToXmlString<T>(this object value)
{
return value.ToXmlString(typeof (T));
}
private static string GetEnumPropertyDebugString(object enumItem, int levels)
private static string? GetEnumPropertyDebugString(object enumItem, int levels)
{
try
{
@@ -657,7 +657,7 @@ namespace Umbraco.Extensions
}
}
private static string GetPropertyDebugString(PropertyInfo propertyInfo, object obj, int levels)
private static string? GetPropertyDebugString(PropertyInfo propertyInfo, object obj, int levels)
{
try
{
@@ -683,7 +683,7 @@ namespace Umbraco.Extensions
// gets a converter for source, that can convert to target, or null if none exists
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static TypeConverter GetCachedSourceTypeConverter(Type source, Type target)
private static TypeConverter? GetCachedSourceTypeConverter(Type source, Type target)
{
var key = new CompositeTypeTypeKey(source, target);
@@ -698,12 +698,13 @@ namespace Umbraco.Extensions
return InputTypeConverterCache[key] = converter;
}
return InputTypeConverterCache[key] = null;
InputTypeConverterCache[key] = null;
return null;
}
// gets a converter for target, that can convert from source, or null if none exists
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static TypeConverter GetCachedTargetTypeConverter(Type source, Type target)
private static TypeConverter? GetCachedTargetTypeConverter(Type source, Type target)
{
var key = new CompositeTypeTypeKey(source, target);
@@ -718,12 +719,13 @@ namespace Umbraco.Extensions
return DestinationTypeConverterCache[key] = converter;
}
return DestinationTypeConverterCache[key] = null;
DestinationTypeConverterCache[key] = null;
return null;
}
// gets the underlying type of a nullable type, or null if the type is not nullable
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Type GetCachedGenericNullableType(Type type)
private static Type? GetCachedGenericNullableType(Type type)
{
if (NullableGenericCache.TryGetValue(type, out var underlyingType))
{
@@ -732,11 +734,12 @@ namespace Umbraco.Extensions
if (type.GetGenericTypeDefinition() == typeof(Nullable<>))
{
Type underlying = Nullable.GetUnderlyingType(type);
Type? underlying = Nullable.GetUnderlyingType(type);
return NullableGenericCache[type] = underlying;
}
return NullableGenericCache[type] = null;
NullableGenericCache[type] = null;
return null;
}
// gets an IConvertible from source to target type, or null if none exists

View File

@@ -523,7 +523,7 @@ namespace Umbraco.Extensions
/// <param name="maxLevel">The level.</param>
/// <returns>The nearest (in down-top order) ancestor of the content, at a level lesser or equal to the specified level.</returns>
/// <remarks>Does not consider the content itself. May return <c>null</c>.</remarks>
public static IPublishedContent Ancestor(this IPublishedContent content, int maxLevel)
public static IPublishedContent? Ancestor(this IPublishedContent content, int maxLevel)
{
return content.EnumerateAncestors(false).FirstOrDefault(x => x.Level <= maxLevel);
}
@@ -535,7 +535,7 @@ namespace Umbraco.Extensions
/// <param name="contentTypeAlias">The content type alias.</param>
/// <returns>The nearest (in down-top order) ancestor of the content, of the specified content type.</returns>
/// <remarks>Does not consider the content itself. May return <c>null</c>.</remarks>
public static IPublishedContent Ancestor(this IPublishedContent content, string contentTypeAlias)
public static IPublishedContent? Ancestor(this IPublishedContent content, string contentTypeAlias)
{
return content.EnumerateAncestors(false).FirstOrDefault(x => x.ContentType.Alias.InvariantEquals(contentTypeAlias));
}
@@ -547,7 +547,7 @@ namespace Umbraco.Extensions
/// <param name="content">The content.</param>
/// <returns>The nearest (in down-top order) ancestor of the content, of the specified content type.</returns>
/// <remarks>Does not consider the content itself. May return <c>null</c>.</remarks>
public static T Ancestor<T>(this IPublishedContent content)
public static T? Ancestor<T>(this IPublishedContent content)
where T : class, IPublishedContent
{
return content.Ancestors<T>().FirstOrDefault();
@@ -562,7 +562,7 @@ namespace Umbraco.Extensions
/// <returns>The ancestor of the content, at the specified level and of the specified content type.</returns>
/// <remarks>Does not consider the content itself. If the ancestor at the specified level is
/// not of the specified type, returns <c>null</c>.</remarks>
public static T Ancestor<T>(this IPublishedContent content, int maxLevel)
public static T? Ancestor<T>(this IPublishedContent content, int maxLevel)
where T : class, IPublishedContent
{
return content.Ancestors<T>(maxLevel).FirstOrDefault();
@@ -586,7 +586,7 @@ namespace Umbraco.Extensions
/// <param name="maxLevel">The level.</param>
/// <returns>The content or its nearest (in down-top order) ancestor, at a level lesser or equal to the specified level.</returns>
/// <remarks>May or may not return the content itself depending on its level. May return <c>null</c>.</remarks>
public static IPublishedContent AncestorOrSelf(this IPublishedContent content, int maxLevel)
public static IPublishedContent? AncestorOrSelf(this IPublishedContent content, int maxLevel)
{
return content.EnumerateAncestors(true).FirstOrDefault(x => x.Level <= maxLevel);
}
@@ -598,7 +598,7 @@ namespace Umbraco.Extensions
/// <param name="contentTypeAlias">The content type.</param>
/// <returns>The content or its nearest (in down-top order) ancestor, of the specified content type.</returns>
/// <remarks>May or may not return the content itself depending on its content type. May return <c>null</c>.</remarks>
public static IPublishedContent AncestorOrSelf(this IPublishedContent content, string contentTypeAlias)
public static IPublishedContent? AncestorOrSelf(this IPublishedContent content, string contentTypeAlias)
{
return content.EnumerateAncestors(true).FirstOrDefault(x => x.ContentType.Alias.InvariantEquals(contentTypeAlias));
}
@@ -610,7 +610,7 @@ namespace Umbraco.Extensions
/// <param name="content">The content.</param>
/// <returns>The content or its nearest (in down-top order) ancestor, of the specified content type.</returns>
/// <remarks>May or may not return the content itself depending on its content type. May return <c>null</c>.</remarks>
public static T AncestorOrSelf<T>(this IPublishedContent content)
public static T? AncestorOrSelf<T>(this IPublishedContent content)
where T : class, IPublishedContent
{
return content.AncestorsOrSelf<T>().FirstOrDefault();
@@ -623,7 +623,7 @@ namespace Umbraco.Extensions
/// <param name="content">The content.</param>
/// <param name="maxLevel">The level.</param>
/// <returns></returns>
public static T AncestorOrSelf<T>(this IPublishedContent content, int maxLevel)
public static T? AncestorOrSelf<T>(this IPublishedContent content, int maxLevel)
where T : class, IPublishedContent
{
return content.AncestorsOrSelf<T>(maxLevel).FirstOrDefault();
@@ -817,17 +817,17 @@ namespace Umbraco.Extensions
return content.DescendantsOrSelf(variationContextAccessor, level, culture).OfType<T>();
}
public static IPublishedContent Descendant(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string? culture = null)
public static IPublishedContent? Descendant(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string? culture = null)
{
return content.Children(variationContextAccessor, culture).FirstOrDefault();
}
public static IPublishedContent Descendant(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, int level, string? culture = null)
public static IPublishedContent? Descendant(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, int level, string? culture = null)
{
return content.EnumerateDescendants(variationContextAccessor, false, culture).FirstOrDefault(x => x.Level == level);
}
public static IPublishedContent DescendantOfType(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string contentTypeAlias, string? culture = null)
public static IPublishedContent? DescendantOfType(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string contentTypeAlias, string? culture = null)
{
return content.EnumerateDescendants(variationContextAccessor, false, culture).FirstOrDefault(x => x.ContentType.Alias.InvariantEquals(contentTypeAlias));
}
@@ -849,12 +849,12 @@ namespace Umbraco.Extensions
return content;
}
public static IPublishedContent DescendantOrSelf(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, int level, string? culture = null)
public static IPublishedContent? DescendantOrSelf(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, int level, string? culture = null)
{
return content.EnumerateDescendants(variationContextAccessor, true, culture).FirstOrDefault(x => x.Level == level);
}
public static IPublishedContent DescendantOrSelfOfType(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string contentTypeAlias, string? culture = null)
public static IPublishedContent? DescendantOrSelfOfType(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string contentTypeAlias, string? culture = null)
{
return content.EnumerateDescendants(variationContextAccessor, true, culture).FirstOrDefault(x => x.ContentType.Alias.InvariantEquals(contentTypeAlias));
}
@@ -978,7 +978,7 @@ namespace Umbraco.Extensions
return content.Children(variationContextAccessor, culture).OfType<T>();
}
public static IPublishedContent FirstChild(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string? culture = null)
public static IPublishedContent? FirstChild(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string? culture = null)
{
return content.Children(variationContextAccessor, culture).FirstOrDefault();
}
@@ -986,28 +986,28 @@ namespace Umbraco.Extensions
/// <summary>
/// Gets the first child of the content, of a given content type.
/// </summary>
public static IPublishedContent FirstChildOfType(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string contentTypeAlias, string? culture = null)
public static IPublishedContent? FirstChildOfType(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string contentTypeAlias, string? culture = null)
{
return content.ChildrenOfType(variationContextAccessor, contentTypeAlias, culture).FirstOrDefault();
}
public static IPublishedContent FirstChild(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, Func<IPublishedContent, bool> predicate, string? culture = null)
public static IPublishedContent? FirstChild(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, Func<IPublishedContent, bool> predicate, string? culture = null)
{
return content.Children(variationContextAccessor, predicate, culture).FirstOrDefault();
}
public static IPublishedContent FirstChild(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, Guid uniqueId, string? culture = null)
public static IPublishedContent? FirstChild(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, Guid uniqueId, string? culture = null)
{
return content.Children(variationContextAccessor, x => x.Key == uniqueId, culture).FirstOrDefault();
}
public static T FirstChild<T>(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string? culture = null)
public static T? FirstChild<T>(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string? culture = null)
where T : class, IPublishedContent
{
return content.Children<T>(variationContextAccessor, culture).FirstOrDefault();
}
public static T FirstChild<T>(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, Func<T, bool> predicate, string? culture = null)
public static T? FirstChild<T>(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, Func<T, bool> predicate, string? culture = null)
where T : class, IPublishedContent
{
return content.Children<T>(variationContextAccessor, culture).FirstOrDefault(predicate);
@@ -1149,7 +1149,7 @@ namespace Umbraco.Extensions
/// <remarks>
/// This is the same as calling <see cref="Umbraco.Web.PublishedContentExtensions.AncestorOrSelf(IPublishedContent, int)" /> with <c>maxLevel</c> set to 1.
/// </remarks>
public static IPublishedContent Root(this IPublishedContent content)
public static IPublishedContent? Root(this IPublishedContent content)
{
return content.AncestorOrSelf(1);
}
@@ -1165,7 +1165,7 @@ namespace Umbraco.Extensions
/// <remarks>
/// This is the same as calling <see cref="Umbraco.Web.PublishedContentExtensions.AncestorOrSelf{T}(IPublishedContent, int)" /> with <c>maxLevel</c> set to 1.
/// </remarks>
public static T Root<T>(this IPublishedContent content)
public static T? Root<T>(this IPublishedContent content)
where T : class, IPublishedContent
{
return content.AncestorOrSelf<T>(1);

View File

@@ -38,7 +38,7 @@ namespace Umbraco.Extensions
}
var valueConverted = value.TryConvertTo<T>();
if (valueConverted)
if (valueConverted.Success.HasValue && valueConverted.Success.Value)
{
return valueConverted.Result;
}
@@ -63,7 +63,7 @@ namespace Umbraco.Extensions
}
var noValueConverted = noValue.TryConvertTo<T>();
if (noValueConverted)
if (noValueConverted.Success.HasValue && noValueConverted.Success.Value)
{
return noValueConverted.Result;
}

View File

@@ -43,7 +43,7 @@ namespace Umbraco.Extensions
{
var nodeIds = path.Split(Constants.CharArrays.Comma, StringSplitOptions.RemoveEmptyEntries)
.Select(x => int.TryParse(x, NumberStyles.Integer, CultureInfo.InvariantCulture, out var output) ? Attempt<int>.Succeed(output) : Attempt<int>.Fail())
.Where(x => x.Success)
.Where(x => x.Success ?? false)
.Select(x=>x.Result)
.Reverse()
.ToArray();
@@ -393,7 +393,7 @@ namespace Umbraco.Extensions
/// <returns>The enum try parse.</returns>
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "By Design")]
[SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "2#", Justification = "By Design")]
public static bool EnumTryParse<T>(this string strType, bool ignoreCase, out T result)
public static bool EnumTryParse<T>(this string strType, bool ignoreCase, out T? result)
{
try
{
@@ -498,7 +498,7 @@ namespace Umbraco.Extensions
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static string FromUrlBase64(this string input)
public static string? FromUrlBase64(this string input)
{
if (input == null) throw new ArgumentNullException(nameof(input));
@@ -522,9 +522,9 @@ namespace Umbraco.Extensions
/// <param name="format">The format.</param>
/// <param name="args">The args.</param>
/// <returns></returns>
public static string InvariantFormat(this string format, params object[] args)
public static string InvariantFormat(this string? format, params object?[] args)
{
return String.Format(CultureInfo.InvariantCulture, format, args);
return string.Format(CultureInfo.InvariantCulture, format ?? string.Empty, args);
}
/// <summary>
@@ -548,7 +548,7 @@ namespace Umbraco.Extensions
/// <param name="compare">The compare.</param>
/// <param name="compareTo">The compare to.</param>
/// <returns></returns>
public static bool InvariantEquals(this string compare, string compareTo)
public static bool InvariantEquals(this string compare, string? compareTo)
{
return String.Equals(compare, compareTo, StringComparison.InvariantCultureIgnoreCase);
}
@@ -590,9 +590,9 @@ namespace Umbraco.Extensions
/// <typeparam name="T"></typeparam>
/// <param name="val"></param>
/// <returns></returns>
public static T ParseInto<T>(this string val)
public static T? ParseInto<T>(this string val)
{
return (T)val.ParseInto(typeof(T));
return (T?)val.ParseInto(typeof(T));
}
/// <summary>
@@ -601,7 +601,7 @@ namespace Umbraco.Extensions
/// <param name="val"></param>
/// <param name="type"></param>
/// <returns></returns>
public static object ParseInto(this string val, Type type)
public static object? ParseInto(this string val, Type type)
{
if (string.IsNullOrEmpty(val) == false)
{
@@ -641,10 +641,15 @@ namespace Umbraco.Extensions
/// <param name="str">Refers to itself</param>
/// <param name="hashType">String with the hash type. See remarks section of the CryptoConfig Class in MSDN docs for a list of possible values.</param>
/// <returns>The hashed string</returns>
private static string GenerateHash(this string str, string hashType)
private static string GenerateHash(this string str, string? hashType)
{
HashAlgorithm? hasher = null;
//create an instance of the correct hashing provider based on the type passed in
var hasher = HashAlgorithm.Create(hashType);
if (hashType is not null)
{
hasher = HashAlgorithm.Create(hashType);
}
if (hasher == null) throw new InvalidOperationException("No hashing type found by name " + hashType);
using (hasher)
{
@@ -1184,7 +1189,7 @@ namespace Umbraco.Extensions
{
algorithm.TransformBlock(namespaceBytes, 0, namespaceBytes.Length, null, 0);
algorithm.TransformFinalBlock(nameBytes, 0, nameBytes.Length);
hash = algorithm.Hash;
hash = algorithm.Hash!;
}
// most bytes from the hash are copied straight to the bytes of the new GUID (steps 5-7, 9, 11-12)
@@ -1221,7 +1226,7 @@ namespace Umbraco.Extensions
/// <summary>
/// Turns an null-or-whitespace string into a null string.
/// </summary>
public static string NullOrWhiteSpaceAsNull(this string text)
public static string? NullOrWhiteSpaceAsNull(this string text)
=> string.IsNullOrWhiteSpace(text) ? null : text;
@@ -1236,7 +1241,7 @@ namespace Umbraco.Extensions
return string.IsNullOrWhiteSpace(path) == false
&& path.IndexOfAny(Path.GetInvalidPathChars().ToArray()) == -1
&& Path.IsPathRooted(path)
&& Path.GetPathRoot(path).Equals(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal) == false;
&& Path.GetPathRoot(path)?.Equals(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal) == false;
}
// FORMAT STRINGS

View File

@@ -15,14 +15,14 @@ namespace Umbraco.Extensions
{
public static class TypeExtensions
{
public static object GetDefaultValue(this Type t)
public static object? GetDefaultValue(this Type t)
{
return t.IsValueType
? Activator.CreateInstance(t)
: null;
}
internal static MethodInfo GetGenericMethod(this Type type, string name, params Type[] parameterTypes)
internal static MethodInfo? GetGenericMethod(this Type type, string name, params Type[] parameterTypes)
{
var methods = type.GetMethods().Where(method => method.Name == name);
@@ -75,12 +75,12 @@ namespace Umbraco.Extensions
return true;
}
public static IEnumerable<Type> GetBaseTypes(this Type type, bool andSelf)
public static IEnumerable<Type?> GetBaseTypes(this Type? type, bool andSelf)
{
if (andSelf)
yield return type;
while ((type = type.BaseType) != null)
while ((type = type?.BaseType) != null)
yield return type;
}
@@ -121,7 +121,7 @@ namespace Umbraco.Extensions
/// </returns>
public static bool IsOfGenericType(this Type type, Type genericType)
{
Type[] args;
Type[]? args;
return type.TryGetGenericArguments(genericType, out args);
}
@@ -132,7 +132,7 @@ namespace Umbraco.Extensions
/// <param name="genericType"></param>
/// <param name="genericArgType"></param>
/// <returns></returns>
public static bool TryGetGenericArguments(this Type type, Type genericType, out Type[] genericArgType)
public static bool TryGetGenericArguments(this Type type, Type genericType, out Type[]? genericArgType)
{
if (type == null)
{
@@ -147,7 +147,7 @@ namespace Umbraco.Extensions
throw new ArgumentException("genericType must be a generic type");
}
Func<Type, Type, Type[]> checkGenericType = (@int, t) =>
Func<Type, Type, Type[]?> checkGenericType = (@int, t) =>
{
if (@int.IsGenericType)
{
@@ -313,34 +313,34 @@ namespace Umbraco.Extensions
return typeof(TInterface).IsAssignableFrom(type);
}
public static TAttribute FirstAttribute<TAttribute>(this Type type)
public static TAttribute? FirstAttribute<TAttribute>(this Type type)
{
return type.FirstAttribute<TAttribute>(true);
}
public static TAttribute FirstAttribute<TAttribute>(this Type type, bool inherit)
public static TAttribute? FirstAttribute<TAttribute>(this Type type, bool inherit)
{
var attrs = type.GetCustomAttributes(typeof(TAttribute), inherit);
return (TAttribute)(attrs.Length > 0 ? attrs[0] : null);
return (TAttribute?)(attrs.Length > 0 ? attrs[0] : null);
}
public static TAttribute FirstAttribute<TAttribute>(this PropertyInfo propertyInfo)
public static TAttribute? FirstAttribute<TAttribute>(this PropertyInfo propertyInfo)
{
return propertyInfo.FirstAttribute<TAttribute>(true);
}
public static TAttribute FirstAttribute<TAttribute>(this PropertyInfo propertyInfo, bool inherit)
public static TAttribute? FirstAttribute<TAttribute>(this PropertyInfo propertyInfo, bool inherit)
{
var attrs = propertyInfo.GetCustomAttributes(typeof(TAttribute), inherit);
return (TAttribute)(attrs.Length > 0 ? attrs[0] : null);
return (TAttribute?)(attrs.Length > 0 ? attrs[0] : null);
}
public static IEnumerable<TAttribute> MultipleAttribute<TAttribute>(this PropertyInfo propertyInfo)
public static IEnumerable<TAttribute>? MultipleAttribute<TAttribute>(this PropertyInfo propertyInfo)
{
return propertyInfo.MultipleAttribute<TAttribute>(true);
}
public static IEnumerable<TAttribute> MultipleAttribute<TAttribute>(this PropertyInfo propertyInfo, bool inherit)
public static IEnumerable<TAttribute>? MultipleAttribute<TAttribute>(this PropertyInfo propertyInfo, bool inherit)
{
var attrs = propertyInfo.GetCustomAttributes(typeof(TAttribute), inherit);
return (attrs.Length > 0 ? attrs.ToList().ConvertAll(input => (TAttribute)input) : null);
@@ -389,8 +389,8 @@ namespace Umbraco.Extensions
var t = c;
while (t != typeof(object))
{
if (t.IsGenericType && t.GetGenericTypeDefinition() == type) return true;
t = t.BaseType;
if (t is not null && t.IsGenericType && t.GetGenericTypeDefinition() == type) return true;
t = t?.BaseType;
}
}
@@ -403,7 +403,7 @@ namespace Umbraco.Extensions
/// </summary>
/// <param name="type">the source type</param>
/// <returns></returns>
public static Type GetEnumeratedType(this Type type)
public static Type? GetEnumeratedType(this Type type)
{
if (typeof(IEnumerable).IsAssignableFrom(type) == false)
return null;
@@ -420,7 +420,7 @@ namespace Umbraco.Extensions
return null;
}
public static T GetCustomAttribute<T>(this Type type, bool inherit)
public static T? GetCustomAttribute<T>(this Type type, bool inherit)
where T : Attribute
{
return type.GetCustomAttributes<T>(inherit).SingleOrDefault();

View File

@@ -154,7 +154,7 @@ namespace Umbraco.Extensions
return new Uri(baseUri.GetLeftPart(UriPartial.Authority) + uri.GetSafeAbsolutePath() + uri.GetSafeQuery());
}
static string GetSafeQuery(this Uri uri)
static string? GetSafeQuery(this Uri uri)
{
if (uri.IsAbsoluteUri)
return uri.Query;

View File

@@ -15,11 +15,11 @@ namespace Umbraco.Extensions
public static Task WaitOneAsync(this WaitHandle handle, int millisecondsTimeout = Timeout.Infinite)
{
var tcs = new TaskCompletionSource<object>();
var tcs = new TaskCompletionSource<object?>();
var callbackHandleInitLock = new object();
lock (callbackHandleInitLock)
{
RegisteredWaitHandle callbackHandle = null;
RegisteredWaitHandle? callbackHandle = null;
// ReSharper disable once RedundantAssignment
callbackHandle = ThreadPool.RegisterWaitForSingleObject(
handle,
@@ -34,7 +34,7 @@ namespace Umbraco.Extensions
{
// ReSharper disable once PossibleNullReferenceException
// ReSharper disable once AccessToModifiedClosure
callbackHandle.Unregister(null);
callbackHandle?.Unregister(null);
}
},
/*state:*/ null,

View File

@@ -35,7 +35,7 @@ namespace Umbraco.Extensions
/// value which itself is <c>null</c>, then variables are ignored.</para>
/// <para>The XPath expression should reference variables as <c>$var</c>.</para>
/// </remarks>
public static XmlNodeList SelectNodes(this XmlNode source, string expression, IEnumerable<XPathVariable> variables)
public static XmlNodeList? SelectNodes(this XmlNode source, string expression, IEnumerable<XPathVariable>? variables)
{
var av = variables == null ? null : variables.ToArray();
return SelectNodes(source, expression, av);
@@ -53,7 +53,7 @@ namespace Umbraco.Extensions
/// value which itself is <c>null</c>, then variables are ignored.</para>
/// <para>The XPath expression should reference variables as <c>$var</c>.</para>
/// </remarks>
public static XmlNodeList SelectNodes(this XmlNode source, XPathExpression expression, IEnumerable<XPathVariable> variables)
public static XmlNodeList? SelectNodes(this XmlNode source, XPathExpression expression, IEnumerable<XPathVariable>? variables)
{
var av = variables == null ? null : variables.ToArray();
return SelectNodes(source, expression, av);
@@ -71,12 +71,12 @@ namespace Umbraco.Extensions
/// value which itself is <c>null</c>, then variables are ignored.</para>
/// <para>The XPath expression should reference variables as <c>$var</c>.</para>
/// </remarks>
public static XmlNodeList SelectNodes(this XmlNode source, string expression, params XPathVariable[] variables)
public static XmlNodeList? SelectNodes(this XmlNode source, string? expression, params XPathVariable[]? variables)
{
if (variables == null || variables.Length == 0 || variables[0] == null)
return source.SelectNodes(expression);
return source.SelectNodes(expression ?? "");
var iterator = source.CreateNavigator().Select(expression, variables);
var iterator = source.CreateNavigator()?.Select(expression ?? "", variables);
return XmlNodeListFactory.CreateNodeList(iterator);
}
@@ -92,12 +92,12 @@ namespace Umbraco.Extensions
/// value which itself is <c>null</c>, then variables are ignored.</para>
/// <para>The XPath expression should reference variables as <c>$var</c>.</para>
/// </remarks>
public static XmlNodeList SelectNodes(this XmlNode source, XPathExpression expression, params XPathVariable[] variables)
public static XmlNodeList SelectNodes(this XmlNode source, XPathExpression expression, params XPathVariable[]? variables)
{
if (variables == null || variables.Length == 0 || variables[0] == null)
return source.SelectNodes(expression);
var iterator = source.CreateNavigator().Select(expression, variables);
var iterator = source.CreateNavigator()?.Select(expression, variables);
return XmlNodeListFactory.CreateNodeList(iterator);
}
@@ -113,7 +113,7 @@ namespace Umbraco.Extensions
/// value which itself is <c>null</c>, then variables are ignored.</para>
/// <para>The XPath expression should reference variables as <c>$var</c>.</para>
/// </remarks>
public static XmlNode SelectSingleNode(this XmlNode source, string expression, IEnumerable<XPathVariable> variables)
public static XmlNode? SelectSingleNode(this XmlNode source, string expression, IEnumerable<XPathVariable>? variables)
{
var av = variables == null ? null : variables.ToArray();
return SelectSingleNode(source, expression, av);
@@ -131,7 +131,7 @@ namespace Umbraco.Extensions
/// value which itself is <c>null</c>, then variables are ignored.</para>
/// <para>The XPath expression should reference variables as <c>$var</c>.</para>
/// </remarks>
public static XmlNode SelectSingleNode(this XmlNode source, XPathExpression expression, IEnumerable<XPathVariable> variables)
public static XmlNode? SelectSingleNode(this XmlNode source, XPathExpression expression, IEnumerable<XPathVariable>? variables)
{
var av = variables == null ? null : variables.ToArray();
return SelectSingleNode(source, expression, av);
@@ -149,12 +149,12 @@ namespace Umbraco.Extensions
/// value which itself is <c>null</c>, then variables are ignored.</para>
/// <para>The XPath expression should reference variables as <c>$var</c>.</para>
/// </remarks>
public static XmlNode SelectSingleNode(this XmlNode source, string expression, params XPathVariable[] variables)
public static XmlNode? SelectSingleNode(this XmlNode source, string expression, params XPathVariable[]? variables)
{
if (variables == null || variables.Length == 0 || variables[0] == null)
return source.SelectSingleNode(expression);
return SelectNodes(source, expression, variables).Cast<XmlNode>().FirstOrDefault();
return SelectNodes(source, expression, variables)?.Cast<XmlNode>().FirstOrDefault();
}
/// <summary>
@@ -169,7 +169,7 @@ namespace Umbraco.Extensions
/// value which itself is <c>null</c>, then variables are ignored.</para>
/// <para>The XPath expression should reference variables as <c>$var</c>.</para>
/// </remarks>
public static XmlNode SelectSingleNode(this XmlNode source, XPathExpression expression, params XPathVariable[] variables)
public static XmlNode? SelectSingleNode(this XmlNode source, XPathExpression expression, params XPathVariable[]? variables)
{
if (variables == null || variables.Length == 0 || variables[0] == null)
return source.SelectSingleNode(expression);
@@ -211,7 +211,7 @@ namespace Umbraco.Extensions
///// </summary>
///// <param name="xElement"></param>
///// <returns></returns>
public static XmlNode ToXmlElement(this XContainer xElement)
public static XmlNode? ToXmlElement(this XContainer xElement)
{
var xmlDocument = new XmlDocument();
using (var xmlReader = xElement.CreateReader())
@@ -235,7 +235,7 @@ namespace Umbraco.Extensions
}
}
public static T RequiredAttributeValue<T>(this XElement xml, string attributeName)
public static T? RequiredAttributeValue<T>(this XElement xml, string attributeName)
{
if (xml == null)
{
@@ -247,14 +247,14 @@ namespace Umbraco.Extensions
throw new InvalidOperationException($"{attributeName} not found in xml");
}
XAttribute attribute = xml.Attribute(attributeName);
XAttribute? attribute = xml.Attribute(attributeName);
if (attribute is null)
{
throw new InvalidOperationException($"{attributeName} not found in xml");
}
Attempt<T> result = attribute.Value.TryConvertTo<T>();
if (result.Success)
if (result.Success.HasValue && result.Success.Value)
{
return result.Result;
}
@@ -262,7 +262,7 @@ namespace Umbraco.Extensions
throw new InvalidOperationException($"{attribute.Value} attribute value cannot be converted to {typeof(T)}");
}
public static T AttributeValue<T>(this XElement xml, string attributeName)
public static T? AttributeValue<T>(this XElement xml, string attributeName)
{
if (xml == null) throw new ArgumentNullException("xml");
if (xml.HasAttributes == false) return default(T);
@@ -270,15 +270,15 @@ namespace Umbraco.Extensions
if (xml.Attribute(attributeName) == null)
return default(T);
var val = xml.Attribute(attributeName).Value;
var val = xml.Attribute(attributeName)?.Value;
var result = val.TryConvertTo<T>();
if (result.Success)
if (result.Success.HasValue && result.Success.Value)
return result.Result;
return default(T);
}
public static T AttributeValue<T>(this XmlNode xml, string attributeName)
public static T? AttributeValue<T>(this XmlNode xml, string attributeName)
{
if (xml == null) throw new ArgumentNullException("xml");
if (xml.Attributes == null) return default(T);
@@ -286,15 +286,15 @@ namespace Umbraco.Extensions
if (xml.Attributes[attributeName] == null)
return default(T);
var val = xml.Attributes[attributeName].Value;
var val = xml.Attributes[attributeName]?.Value;
var result = val.TryConvertTo<T>();
if (result.Success)
if (result.Success.HasValue && result.Success.Value)
return result.Result;
return default(T);
}
public static XElement GetXElement(this XmlNode node)
public static XElement? GetXElement(this XmlNode node)
{
XDocument xDoc = new XDocument();
using (XmlWriter xmlWriter = xDoc.CreateWriter())
@@ -302,7 +302,7 @@ namespace Umbraco.Extensions
return xDoc.Root;
}
public static XmlNode GetXmlNode(this XContainer element)
public static XmlNode? GetXmlNode(this XContainer element)
{
using (var xmlReader = element.CreateReader())
{
@@ -312,9 +312,15 @@ namespace Umbraco.Extensions
}
}
public static XmlNode GetXmlNode(this XContainer element, XmlDocument xmlDoc)
public static XmlNode? GetXmlNode(this XContainer element, XmlDocument xmlDoc)
{
return xmlDoc.ImportNode(element.GetXmlNode(), true);
var node = element.GetXmlNode();
if (node is not null)
{
return xmlDoc.ImportNode(node, true);
}
return null;
}
// this exists because

View File

@@ -23,7 +23,7 @@ namespace Umbraco.Cms.Core.Xml
/// <remarks>The underlying XML store used to issue the query must be
/// an object inheriting <see cref="XmlNode"/>, such as
/// <see cref="XmlDocument"/>.</remarks>
public static XmlNodeList CreateNodeList(XPathNodeIterator iterator)
public static XmlNodeList CreateNodeList(XPathNodeIterator? iterator)
{
return new XmlNodeListIterator(iterator);
}
@@ -34,12 +34,12 @@ namespace Umbraco.Cms.Core.Xml
private class XmlNodeListIterator : XmlNodeList
{
readonly XPathNodeIterator _iterator;
readonly XPathNodeIterator? _iterator;
readonly IList<XmlNode> _nodes = new List<XmlNode>();
public XmlNodeListIterator(XPathNodeIterator iterator)
public XmlNodeListIterator(XPathNodeIterator? iterator)
{
_iterator = iterator.Clone();
_iterator = iterator?.Clone();
}
public override System.Collections.IEnumerator GetEnumerator()
@@ -47,7 +47,7 @@ namespace Umbraco.Cms.Core.Xml
return new XmlNodeListEnumerator(this);
}
public override XmlNode Item(int index)
public override XmlNode? Item(int index)
{
if (index >= _nodes.Count)
@@ -73,7 +73,7 @@ namespace Umbraco.Cms.Core.Xml
/// </summary>
private void ReadToEnd()
{
while (_iterator.MoveNext())
while (_iterator is not null && _iterator.MoveNext())
{
var node = _iterator.Current as IHasXmlNode;
// Check IHasXmlNode interface.
@@ -92,7 +92,7 @@ namespace Umbraco.Cms.Core.Xml
{
while (_nodes.Count <= to)
{
if (_iterator.MoveNext())
if (_iterator is not null && _iterator.MoveNext())
{
var node = _iterator.Current as IHasXmlNode;
// Check IHasXmlNode interface.
@@ -159,7 +159,7 @@ namespace Umbraco.Cms.Core.Xml
return true;
}
object System.Collections.IEnumerator.Current
object? System.Collections.IEnumerator.Current
{
get
{