See More

using System.Diagnostics; using System.Reflection; namespace BytecodeApi; ///

/// Provides methods and properties serving as a general object manipulation helper class. /// public static class CSharp { /// /// Returns the converted version of , if it is of the specified type; otherwise, returns (). /// /// The type to which to convert to. /// The to be converted. /// /// The converted version of , if it is of the specified type; otherwise, returns (). /// public static T? CastOrDefault(object? obj) { return obj is T castedObject ? castedObject : default; } /// /// Performs an and disposes , if is an . This is useful if the given only indirectly inherits and therefore the keyword cannot be used. /// /// The to be disposed. If is not an , it will not be disposed. /// The to be performed before the method is called. This is equivalent to the body of the statement. public static void Using(object? obj, Action action) { Check.ArgumentNull(action); try { action(); } finally { (obj as IDisposable)?.Dispose(); } } /// /// Performs an and disposes all objects in the specified array that are . /// /// An array of objects to be disposed. /// The to be performed before the method is called. This is equivalent to the body of the statement. public static void Using(object?[] objects, Action action) { Check.ArgumentNull(objects); Check.ArgumentNull(action); try { action(); } finally { foreach (object? obj in objects) { (obj as IDisposable)?.Dispose(); } } } /// /// Copies the contents of properties and fields of an to another of a different by comparing property and field names. A new instance of is created. /// Values are only copied, if the property or field is of equivalent type. This includes conversion between mixed values (e.g. and ?), and between and numeric values. Differing types are attempted to convert (e.g. and ). If conversion fails, the default value of the destination type is used. /// /// The type of the to copy the contents to. /// The to copy the contents from. /// /// The new instance of this method creates, with properties and fields copied from . /// public static TDest ConvertObject(object obj) where TDest : class { return ConvertObject(obj, ConvertObjectOptions.None); } /// /// Copies the contents of properties and fields of an to another of a different by comparing property and field names. A new instance of is created. /// Values are only copied, if the property or field is of equivalent type. This includes conversion between mixed values (e.g. and ?), and between and numeric values. Differing types are attempted to convert (e.g. and ). If conversion fails, the default value of the destination type is used. /// /// The type of the to copy the contents to. /// The to copy the contents from. /// The flags that specify comparison and copy behavior. /// /// The new instance of this method creates, with properties and fields copied from . /// public static TDest ConvertObject(object obj, ConvertObjectOptions flags) where TDest : class { Check.ArgumentNull(obj); TDest dest = Activator.CreateInstance(); ConvertObject(obj, dest, flags); return dest; } /// /// Copies the contents of properties and fields of an to another of a different by comparing property and field names. /// Values are only copied, if the property or field is of equivalent type. This includes conversion between mixed values (e.g. and ?), and between and numeric values. Differing types are attempted to convert (e.g. and ). If conversion fails, the default value of the destination type is used. /// /// The type of the to copy the contents to. /// The to copy the contents from. /// The to copy the contents to. public static void ConvertObject(object obj, TDest dest) where TDest : class { ConvertObject(obj, dest, ConvertObjectOptions.None); } /// /// Copies the contents of properties and fields of an to another of a different by comparing property and field names. /// Values are only copied, if the property or field is of equivalent type. This includes conversion between mixed values (e.g. and ?), and between and numeric values. Differing types are attempted to convert (e.g. and ). If conversion fails, the default value of the destination type is used. /// /// The type of the to copy the contents to. /// The to copy the contents from. /// The to copy the contents to. /// The flags that specify comparison and copy behavior. public static void ConvertObject(object obj, TDest dest, ConvertObjectOptions flags) where TDest : class { Check.ArgumentNull(obj); Check.ArgumentNull(dest); BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public; if (flags.HasFlag(ConvertObjectOptions.IgnoreCase)) bindingFlags |= BindingFlags.IgnoreCase; if (flags.HasFlag(ConvertObjectOptions.NonPublic)) bindingFlags |= BindingFlags.NonPublic; if (flags.HasFlag(ConvertObjectOptions.Static)) bindingFlags |= BindingFlags.Static; if (!flags.HasFlag(ConvertObjectOptions.IgnoreProperties)) { foreach (PropertyInfo sourceProperty in obj.GetType().GetProperties(bindingFlags)) { if (dest.GetType().GetProperty(sourceProperty.Name, bindingFlags) is PropertyInfo destProperty && destProperty.SetMethod != null) { Process ( sourceProperty.PropertyType, destProperty.PropertyType, () => sourceProperty.GetValue(obj), value => destProperty.SetValue(dest, value) ); } if (flags.HasFlag(ConvertObjectOptions.PropertiesToFields) && dest.GetType().GetField(sourceProperty.Name, bindingFlags) is FieldInfo destField) { Process ( sourceProperty.PropertyType, destField.FieldType, () => sourceProperty.GetValue(obj), value => destField.SetValue(dest, value) ); } } } if (!flags.HasFlag(ConvertObjectOptions.IgnoreFields)) { foreach (FieldInfo sourceField in obj.GetType().GetFields(bindingFlags)) { if (dest.GetType().GetField(sourceField.Name, bindingFlags) is FieldInfo destField) { Process ( sourceField.FieldType, destField.FieldType, () => sourceField.GetValue(obj), value => destField.SetValue(dest, value) ); } if (flags.HasFlag(ConvertObjectOptions.FieldsToProperties) && dest.GetType().GetProperty(sourceField.Name, bindingFlags) is PropertyInfo destProperty && destProperty.SetMethod != null) { Process ( sourceField.FieldType, destProperty.PropertyType, () => sourceField.GetValue(obj), value => destProperty.SetValue(dest, value) ); } } } static void Process(Type sourceType, Type destType, Func getValue, Action setValue) { GetEffectiveType(ref sourceType); GetEffectiveType(ref destType); if (sourceType == destType) { setValue(getValue()); return; } else { try { setValue(Convert.ChangeType(getValue(), destType)); return; } catch { } } setValue(null); } static void GetEffectiveType(ref Type type) { if (Nullable.GetUnderlyingType(type) is Type nullable) { type = nullable; } if (type.IsEnum) { type = type.GetEnumUnderlyingType(); } } } /// /// Invokes an and handles any exception. Returns on successful execution and , if an exception was thrown. /// /// The to be invoked. /// /// , on successful execution and /// , if an exception was thrown. /// public static bool Try(Action action) { Check.ArgumentNull(action); try { action(); return true; } catch { return false; } } /// /// Schedules a and handles any exception. Returns on successful execution and , if an exception was thrown. /// /// The to be scheduled. /// /// , on successful execution and /// , if an exception was thrown. /// public static async Task Try(Func task) { Check.ArgumentNull(task); try { await task(); return true; } catch { return false; } } /// /// Schedules a and handles any exception. Returns on successful execution and , if an exception was thrown. /// /// The to be scheduled. /// /// , on successful execution and /// , if an exception was thrown. /// public static async Task Try(Task task) { Check.ArgumentNull(task); try { await task; return true; } catch { return false; } } /// /// Invokes a and handles any exception. Returns the result of on successful execution and () if an exception was thrown. /// /// The return type of . /// The to be invoked. /// /// The result of , on successful execution and /// (), if an exception was thrown. /// public static T? Try(Func func) { return Try(func, default(T)); } /// /// Invokes a and handles any exception. Returns the result of on successful execution and , if an exception was thrown. /// /// The return type of . /// The to be invoked. /// The default value that is returned if an exception was thrown. /// /// The result of , on successful execution and /// , if an exception was thrown. /// public static T Try(Func func, T defaultValue) { Check.ArgumentNull(func); try { return func(); } catch { return defaultValue; } } /// /// Invokes a and handles any exception. Returns the result of on successful execution and invokes and returns , if an exception was thrown. /// /// The return type of . /// The to be invoked. /// The that is invoked and whose result is returned, if an exception was thrown. /// /// The result of , on successful execution and /// The result of , if an exception was thrown. /// public static T Try(Func func, Func defaultValue) { Check.ArgumentNull(func); Check.ArgumentNull(defaultValue); try { return func(); } catch { return defaultValue(); } } /// /// Schedules a and handles any exception. Returns the result of on successful execution and () if an exception was thrown. /// /// The return type of . /// The to be scheduled. /// /// The result of , on successful execution and /// (), if an exception was thrown. /// public static Task Try(Func> task) { return Try(task, default(T)); } /// /// Schedules a and handles any exception. Returns the result of on successful execution and , if an exception was thrown. /// /// The return type of . /// The to be scheduled. /// The default value that is returned if an exception was thrown. /// /// The result of , on successful execution and /// , if an exception was thrown. /// public static async Task Try(Func> task, T defaultValue) { Check.ArgumentNull(task); try { return await task(); } catch { return defaultValue; } } /// /// Schedules a and handles any exception. Returns the result of on successful execution and invokes and returns , if an exception was thrown. /// /// The return type of . /// The to be scheduled. /// The that is invoked and whose result is returned, if an exception was thrown. /// /// The result of , on successful execution and /// The result of , if an exception was thrown. /// public static async Task Try(Func> task, Func defaultValue) { Check.ArgumentNull(task); Check.ArgumentNull(defaultValue); try { return await task(); } catch { return defaultValue(); } } /// /// Schedules a and handles any exception. Returns the result of on successful execution and () if an exception was thrown. /// /// The return type of . /// The to be scheduled. /// /// The result of , on successful execution and /// (), if an exception was thrown. /// public static Task Try(Task task) { return Try(task, default(T)); } /// /// Schedules a and handles any exception. Returns the result of on successful execution and , if an exception was thrown. /// /// The return type of . /// The to be scheduled. /// The default value that is returned if an exception was thrown. /// /// The result of , on successful execution and /// , if an exception was thrown. /// public static async Task Try(Task task, T defaultValue) { Check.ArgumentNull(task); try { return await task; } catch { return defaultValue; } } /// /// Schedules a and handles any exception. Returns the result of on successful execution and invokes and returns , if an exception was thrown. /// /// The return type of . /// The to be scheduled. /// The that is invoked and whose result is returned, if an exception was thrown. /// /// The result of , on successful execution and /// The result of , if an exception was thrown. /// public static async Task Try(Task task, Func defaultValue) { Check.ArgumentNull(task); Check.ArgumentNull(defaultValue); try { return await task; } catch { return defaultValue(); } } /// /// Attempts to invoke an up to a defined number of times until successfully returned without throwing an exception. If throws an exception on the last time, the exception is rethrown. /// /// The to be invoked. /// A value indicating how many times is attempted before the final exception is rethrown. public static void Retry(Action action, int attempts) { Retry(action, attempts, TimeSpan.Zero); } /// /// Attempts to invoke an up to a defined number of times until successfully returned without throwing an exception. If throws an exception on the last time, the exception is rethrown. Between each call of that throws an exception, a delay is waited. /// /// The to be invoked. /// A value indicating how many times is attempted before the final exception is rethrown. /// A value representing the wait period between each call of that throws an exception. public static void Retry(Action action, int attempts, TimeSpan delay) { Check.ArgumentNull(action); Check.ArgumentOutOfRangeEx.Greater0(attempts); Check.ArgumentOutOfRangeEx.GreaterEqual0(delay); for (; ; attempts--) { try { action(); return; } catch when (attempts <= 1) { throw; } catch { Thread.Sleep(delay); } } } /// /// Attempts to schedule a up to a defined number of times until successfully returned without throwing an exception. If throws an exception on the last time, the exception is rethrown. /// /// The to be scheduled. /// A value indicating how many times is attempted before the final exception is rethrown. public static Task Retry(Func task, int attempts) { return Retry(task, attempts, TimeSpan.Zero); } /// /// Attempts to schedule a up to a defined number of times until successfully returned without throwing an exception. If throws an exception on the last time, the exception is rethrown. Between each call of that throws an exception, a delay is waited. /// /// The to be scheduled. /// A value indicating how many times is attempted before the final exception is rethrown. /// A value representing the wait period between each call of that throws an exception. public static async Task Retry(Func task, int attempts, TimeSpan delay) { Check.ArgumentNull(task); Check.ArgumentOutOfRangeEx.Greater0(attempts); Check.ArgumentOutOfRangeEx.GreaterEqual0(delay); for (; ; attempts--) { try { await task(); return; } catch when (attempts <= 1) { throw; } catch { await Task.Delay(delay); } } } /// /// Attempts to invoke a up to a defined number of times until successfully returns a value without throwing an exception. If throws an exception on the last time, the exception is rethrown. /// /// The return type of . /// The to be invoked. /// A value indicating how many times is attempted before the final exception is rethrown. /// /// The result of , if successfully returned a value in the given number of attempts without throwing an exception; /// otherwise, rethrows the exception. /// public static T Retry(Func func, int attempts) { return Retry(func, attempts, TimeSpan.Zero); } /// /// Attempts to invoke a up to a defined number of times until successfully returns a value without throwing an exception. If throws an exception on the last time, the exception is rethrown. Between each call of that throws an exception, a delay is waited. /// /// The return type of . /// The to be invoked. /// A value indicating how many times is attempted before the final exception is rethrown. /// A value representing the wait period between each call of that throws an exception. /// /// The result of , if successfully returned a value in the given number of attempts without throwing an exception; /// otherwise, rethrows the exception. /// public static T Retry(Func func, int attempts, TimeSpan delay) { Check.ArgumentNull(func); Check.ArgumentOutOfRangeEx.Greater0(attempts); Check.ArgumentOutOfRangeEx.GreaterEqual0(delay); for (; ; attempts--) { try { return func(); } catch when (attempts <= 1) { throw; } catch { Thread.Sleep(delay); } } } /// /// Attempts to schedule a up to a defined number of times until successfully returns a value without throwing an exception. If throws an exception on the last time, the exception is rethrown. /// /// The return type of . /// The to be scheduled. /// A value indicating how many times is attempted before the final exception is rethrown. /// /// The result of , if successfully returned a value in the given number of attempts without throwing an exception; /// otherwise, rethrows the exception. /// public static Task Retry(Func> task, int attempts) { return Retry(task, attempts, TimeSpan.Zero); } /// /// Attempts to schedule a up to a defined number of times until successfully returns a value without throwing an exception. If throws an exception on the last time, the exception is rethrown. Between each call of that throws an exception, a delay is waited. /// /// The return type of . /// The to be scheduled. /// A value indicating how many times is attempted before the final exception is rethrown. /// A value representing the wait period between each call of that throws an exception. /// /// The result of , if successfully returned a value in the given number of attempts without throwing an exception; /// otherwise, rethrows the exception. /// public static async Task Retry(Func> task, int attempts, TimeSpan delay) { Check.ArgumentNull(task); Check.ArgumentOutOfRangeEx.Greater0(attempts); Check.ArgumentOutOfRangeEx.GreaterEqual0(delay); for (; ; attempts--) { try { return await task(); } catch when (attempts <= 1) { throw; } catch { await Task.Delay(delay); } } } /// /// Invokes a until the result of is or has been reached. If does not return in this timeframe, is returned, otherwise, . /// /// The to be tested. /// A value representing the total time for to be tested. /// /// , if returned in the specified ; /// otherwise, . /// public static bool Timeout(Func func, TimeSpan timeout) { return Timeout(func, timeout, TimeSpan.Zero); } /// /// Invokes a until the result of is or has been reached. If does not return in this timeframe, is returned, otherwise, . Between each call of that returns , a delay is waited. /// /// The to be tested. /// A value representing the total time for to be tested. /// A value representing the wait period between each call of that returns . /// /// , if returned in the specified ; /// otherwise, . /// public static bool Timeout(Func func, TimeSpan timeout, TimeSpan delay) { Check.ArgumentNull(func); Check.ArgumentOutOfRangeEx.GreaterEqual0(timeout); Check.ArgumentOutOfRangeEx.GreaterEqual0(delay); for (Stopwatch stopwatch = Stopwatch.StartNew(); stopwatch.Elapsed < timeout; Thread.Sleep(delay)) { if (func()) { return true; } } return false; } /// /// Schedules a until the result of is or has been reached. If does not return in this timeframe, is returned, otherwise, . /// /// The to be scheduled. /// A value representing the total time for to be tested. /// /// , if returned in the specified ; /// otherwise, . /// public static Task Timeout(Func> task, TimeSpan timeout) { return Timeout(task, timeout, TimeSpan.Zero); } /// /// Schedules a until the result of is or has been reached. If does not return in this timeframe, is returned, otherwise, . Between each call of that returns , a delay is waited. /// /// The to be scheduled. /// A value representing the total time for to be tested. /// A value representing the wait period between each call of that returns . /// /// , if returned in the specified ; /// otherwise, . /// public static async Task Timeout(Func> task, TimeSpan timeout, TimeSpan delay) { Check.ArgumentNull(task); Check.ArgumentOutOfRangeEx.GreaterEqual0(timeout); Check.ArgumentOutOfRangeEx.GreaterEqual0(delay); for (Stopwatch stopwatch = Stopwatch.StartNew(); stopwatch.Elapsed < timeout; await Task.Delay(delay)) { if (await task()) { return true; } } return false; } /// /// Returns , if is an of the specified . If is not of the specified , or is of a that inherits , is returned. /// /// The to check. /// The to compare to the type of . /// /// , if is an of the specified ; /// , If is not of the specified , or is of a that inherits . /// public static bool IsType([NotNullWhen(true)] object? obj, Type type) { Check.ArgumentNull(type); return obj?.GetType() == type; } /// /// Returns , if is an of the specified type. If is not of the specified type, or is of a type that inherits , is returned. /// /// The type to compare to the type of . /// The to check. /// /// , if is an of the specified type; /// , If is not of the specified type, or is of a type that inherits . /// public static bool IsType([NotNullWhen(true)] object? obj) { return obj?.GetType() == typeof(T); } /// /// Returns , if and are of the same , of if both objects are . /// /// The first to compare. /// The second to compare. /// /// , if and are of the same , of if both objects are ; /// otherwise, . /// public static bool TypeEquals(object? objA, object? objB) { return objA?.GetType() == objB?.GetType(); } /// /// Invokes an and measures the time until returned. /// /// The to be invoked. /// /// A value with the time took to return. /// public static TimeSpan MeasureTime(Action action) { Check.ArgumentNull(action); Stopwatch stopwatch = Stopwatch.StartNew(); action(); stopwatch.Stop(); return stopwatch.Elapsed; } /// /// Schedules a and measures the time until finished. /// /// The to be scheduled. /// /// A value with the time took to finish. /// public static async Task MeasureTime(Func task) { Check.ArgumentNull(task); Stopwatch stopwatch = Stopwatch.StartNew(); await task(); stopwatch.Stop(); return stopwatch.Elapsed; } /// /// Schedules a and measures the time until finished. /// /// The to be scheduled. /// /// A value with the time took to finish. /// public static async Task MeasureTime(Task task) { Check.ArgumentNull(task); Stopwatch stopwatch = Stopwatch.StartNew(); await task; stopwatch.Stop(); return stopwatch.Elapsed; } /// /// Runs the specified synchronously and waits for the task to finish. /// /// The task to run. public static void RunTask(Func task) { Task.Run(async () => await task()).Wait(); } /// /// Runs the specified synchronously and waits for the task to finish. /// /// The task to run. public static void RunTask(Task task) { Task.Run(async () => await task).Wait(); } /// /// Runs the specified synchronously and waits for the task to finish. /// /// The type of the . /// The task to run. /// /// The value that returned. /// public static T RunTask(Func> task) { T result = default!; Task.Run(async () => result = await task()).Wait(); return result; } /// /// Runs the specified synchronously and waits for the task to finish. /// /// The type of the . /// The task to run. /// /// The value that returned. /// public static T RunTask(Task task) { T result = default!; Task.Run(async () => result = await task).Wait(); return result; } }