Code style - Use file scoped namespaces

Code style - Ran code cleanup
This commit is contained in:
Robert committed 2022-08-21 11:36:15 +02:00
1 parent e68e16df4d
commit f6090dc296
691 files changed
+37301 -38119

No files matched your search

@@ -1,32 +1,31 @@
using System.IO;
namespace Artemis.Core
namespace Artemis.Core;
internal static class DirectoryInfoExtensions
{
internal static class DirectoryInfoExtensions
public static void CopyFilesRecursively(this DirectoryInfo source, DirectoryInfo target)
{
public static void CopyFilesRecursively(this DirectoryInfo source, DirectoryInfo target)
foreach (DirectoryInfo dir in source.GetDirectories())
CopyFilesRecursively(dir, target.CreateSubdirectory(dir.Name));
foreach (FileInfo file in source.GetFiles())
file.CopyTo(Path.Combine(target.FullName, file.Name));
}
public static void DeleteRecursively(this DirectoryInfo baseDir)
{
if (!baseDir.Exists)
return;
foreach (DirectoryInfo dir in baseDir.EnumerateDirectories())
DeleteRecursively(dir);
FileInfo[] files = baseDir.GetFiles();
foreach (FileInfo file in files)
{
foreach (DirectoryInfo dir in source.GetDirectories())
CopyFilesRecursively(dir, target.CreateSubdirectory(dir.Name));
foreach (FileInfo file in source.GetFiles())
file.CopyTo(Path.Combine(target.FullName, file.Name));
file.IsReadOnly = false;
file.Delete();
}
public static void DeleteRecursively(this DirectoryInfo baseDir)
{
if (!baseDir.Exists)
return;
foreach (DirectoryInfo dir in baseDir.EnumerateDirectories())
DeleteRecursively(dir);
FileInfo[] files = baseDir.GetFiles();
foreach (FileInfo file in files)
{
file.IsReadOnly = false;
file.Delete();
}
baseDir.Delete();
}
baseDir.Delete();
}
}
+12 -13
View File
@@ -1,22 +1,21 @@
using System;
using System.Runtime.CompilerServices;
namespace Artemis.Core
namespace Artemis.Core;
/// <summary>
/// A static class providing <see cref="double" /> extensions
/// </summary>
public static class DoubleExtensions
{
/// <summary>
/// A static class providing <see cref="double" /> extensions
/// Rounds the provided number away to zero and casts the result to an <see cref="int" />
/// </summary>
public static class DoubleExtensions
/// <param name="number">The number to round</param>
/// <returns>The rounded number as an integer</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int RoundToInt(this double number)
{
/// <summary>
/// Rounds the provided number away to zero and casts the result to an <see cref="int" />
/// </summary>
/// <param name="number">The number to round</param>
/// <returns>The rounded number as an integer</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int RoundToInt(this double number)
{
return (int) Math.Round(number, MidpointRounding.AwayFromZero);
}
return (int) Math.Round(number, MidpointRounding.AwayFromZero);
}
}
+12 -13
View File
@@ -1,22 +1,21 @@
using System;
using System.Runtime.CompilerServices;
namespace Artemis.Core
namespace Artemis.Core;
/// <summary>
/// A static class providing <see cref="float" /> extensions
/// </summary>
public static class FloatExtensions
{
/// <summary>
/// A static class providing <see cref="float" /> extensions
/// Rounds the provided number away to zero and casts the result to an <see cref="int" />
/// </summary>
public static class FloatExtensions
/// <param name="number">The number to round</param>
/// <returns>The rounded number as an integer</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int RoundToInt(this float number)
{
/// <summary>
/// Rounds the provided number away to zero and casts the result to an <see cref="int" />
/// </summary>
/// <param name="number">The number to round</param>
/// <returns>The rounded number as an integer</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int RoundToInt(this float number)
{
return (int) MathF.Round(number, MidpointRounding.AwayFromZero);
}
return (int) MathF.Round(number, MidpointRounding.AwayFromZero);
}
}
@@ -19,35 +19,33 @@
#endregion
using System;
using System.Collections.Generic;
namespace Artemis.Core
namespace Artemis.Core;
/// <summary>
/// A static class providing <see cref="IEnumerable{T}" /> extensions
/// </summary>
// ReSharper disable once InconsistentNaming
public static class IEnumerableExtensions
{
/// <summary>
/// A static class providing <see cref="IEnumerable{T}" /> extensions
/// Returns the index of the provided element inside the read only collection
/// </summary>
// ReSharper disable once InconsistentNaming
public static class IEnumerableExtensions
/// <typeparam name="T">The type of element to find</typeparam>
/// <param name="self">The collection to search in</param>
/// <param name="elementToFind">The element to find</param>
/// <returns>If found, the index of the element to find; otherwise -1</returns>
public static int IndexOf<T>(this IReadOnlyCollection<T> self, T elementToFind)
{
/// <summary>
/// Returns the index of the provided element inside the read only collection
/// </summary>
/// <typeparam name="T">The type of element to find</typeparam>
/// <param name="self">The collection to search in</param>
/// <param name="elementToFind">The element to find</param>
/// <returns>If found, the index of the element to find; otherwise -1</returns>
public static int IndexOf<T>(this IReadOnlyCollection<T> self, T elementToFind)
int i = 0;
foreach (T element in self)
{
int i = 0;
foreach (T element in self)
{
if (Equals(element, elementToFind))
return i;
i++;
}
return -1;
if (Equals(element, elementToFind))
return i;
i++;
}
return -1;
}
}
@@ -1,41 +1,41 @@
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using System.Text;
namespace Artemis.Core
namespace Artemis.Core;
/// <summary>
/// A static class providing <see cref="Process" /> extensions
/// </summary>
[SuppressMessage("Design", "CA1060:Move pinvokes to native methods class", Justification = "I don't care, piss off")]
public static class ProcessExtensions
{
/// <summary>
/// A static class providing <see cref="Process" /> extensions
/// Gets the file name of the given process
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1060:Move pinvokes to native methods class", Justification = "I don't care, piss off")]
public static class ProcessExtensions
/// <param name="p">The process</param>
/// <returns>The filename of the given process</returns>
public static string GetProcessFilename(this Process p)
{
/// <summary>
/// Gets the file name of the given process
/// </summary>
/// <param name="p">The process</param>
/// <returns>The filename of the given process</returns>
public static string GetProcessFilename(this Process p)
{
int capacity = 2000;
StringBuilder builder = new(capacity);
IntPtr ptr = OpenProcess(ProcessAccessFlags.QueryLimitedInformation, false, p.Id);
if (!QueryFullProcessImageName(ptr, 0, builder, ref capacity)) return string.Empty;
int capacity = 2000;
StringBuilder builder = new(capacity);
IntPtr ptr = OpenProcess(ProcessAccessFlags.QueryLimitedInformation, false, p.Id);
if (!QueryFullProcessImageName(ptr, 0, builder, ref capacity)) return string.Empty;
return builder.ToString();
}
return builder.ToString();
}
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
private static extern bool QueryFullProcessImageName([In] IntPtr hProcess, [In] int dwFlags, [Out] StringBuilder lpExeName, ref int lpdwSize);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
private static extern bool QueryFullProcessImageName([In] IntPtr hProcess, [In] int dwFlags, [Out] StringBuilder lpExeName, ref int lpdwSize);
[DllImport("kernel32.dll")]
private static extern IntPtr OpenProcess(ProcessAccessFlags processAccess, bool bInheritHandle, int processId);
[DllImport("kernel32.dll")]
private static extern IntPtr OpenProcess(ProcessAccessFlags processAccess, bool bInheritHandle, int processId);
[Flags]
private enum ProcessAccessFlags : uint
{
QueryLimitedInformation = 0x00001000
}
[Flags]
private enum ProcessAccessFlags : uint
{
QueryLimitedInformation = 0x00001000
}
}
@@ -2,39 +2,38 @@
using RGB.NET.Core;
using SkiaSharp;
namespace Artemis.Core
namespace Artemis.Core;
internal static class RgbDeviceExtensions
{
internal static class RgbDeviceExtensions
public static string GetDeviceIdentifier(this IRGBDevice rgbDevice)
{
public static string GetDeviceIdentifier(this IRGBDevice rgbDevice)
{
StringBuilder builder = new();
builder.Append(rgbDevice.DeviceInfo.DeviceName);
builder.Append('-');
builder.Append(rgbDevice.DeviceInfo.Manufacturer);
builder.Append('-');
builder.Append(rgbDevice.DeviceInfo.Model);
builder.Append('-');
builder.Append(rgbDevice.DeviceInfo.DeviceType);
return builder.ToString();
}
StringBuilder builder = new();
builder.Append(rgbDevice.DeviceInfo.DeviceName);
builder.Append('-');
builder.Append(rgbDevice.DeviceInfo.Manufacturer);
builder.Append('-');
builder.Append(rgbDevice.DeviceInfo.Model);
builder.Append('-');
builder.Append(rgbDevice.DeviceInfo.DeviceType);
return builder.ToString();
}
}
internal static class RgbRectangleExtensions
{
public static SKRect ToSKRect(this Rectangle rectangle)
{
return SKRect.Create(
rectangle.Location.X,
rectangle.Location.Y,
rectangle.Size.Width,
rectangle.Size.Height
);
}
internal static class RgbRectangleExtensions
public static SKRectI ToSKRectI(this Rectangle rectangle)
{
public static SKRect ToSKRect(this Rectangle rectangle)
{
return SKRect.Create(
rectangle.Location.X,
rectangle.Location.Y,
rectangle.Size.Width,
rectangle.Size.Height
);
}
public static SKRectI ToSKRectI(this Rectangle rectangle)
{
return SKRectI.Round(ToSKRect(rectangle));
}
return SKRectI.Round(ToSKRect(rectangle));
}
}
@@ -2,77 +2,76 @@
using RGB.NET.Core;
using SkiaSharp;
namespace Artemis.Core
namespace Artemis.Core;
/// <summary>
/// A static class providing <see cref="SKColor" /> extensions
/// </summary>
public static class SKColorExtensions
{
/// <summary>
/// A static class providing <see cref="SKColor" /> extensions
/// Converts hte SKColor to an RGB.NET color
/// </summary>
public static class SKColorExtensions
/// <param name="color">The color to convert</param>
/// <returns>The RGB.NET color</returns>
public static Color ToRgbColor(this SKColor color)
{
/// <summary>
/// Converts hte SKColor to an RGB.NET color
/// </summary>
/// <param name="color">The color to convert</param>
/// <returns>The RGB.NET color</returns>
public static Color ToRgbColor(this SKColor color)
{
return new Color(color.Alpha, color.Red, color.Green, color.Blue);
}
return new Color(color.Alpha, color.Red, color.Green, color.Blue);
}
/// <summary>
/// Interpolates a color between the <paramref name="from" /> and <paramref name="to" /> color.
/// </summary>
/// <param name="from">The first color</param>
/// <param name="to">The second color</param>
/// <param name="progress">A value between 0 and 1</param>
/// <returns>The interpolated color</returns>
public static SKColor Interpolate(this SKColor from, SKColor to, float progress)
{
int redDiff = to.Red - from.Red;
int greenDiff = to.Green - from.Green;
int blueDiff = to.Blue - from.Blue;
int alphaDiff = to.Alpha - from.Alpha;
/// <summary>
/// Interpolates a color between the <paramref name="from" /> and <paramref name="to" /> color.
/// </summary>
/// <param name="from">The first color</param>
/// <param name="to">The second color</param>
/// <param name="progress">A value between 0 and 1</param>
/// <returns>The interpolated color</returns>
public static SKColor Interpolate(this SKColor from, SKColor to, float progress)
{
int redDiff = to.Red - from.Red;
int greenDiff = to.Green - from.Green;
int blueDiff = to.Blue - from.Blue;
int alphaDiff = to.Alpha - from.Alpha;
return new SKColor(
ClampToByte(from.Red + redDiff * progress),
ClampToByte(from.Green + greenDiff * progress),
ClampToByte(from.Blue + blueDiff * progress),
ClampToByte(from.Alpha + alphaDiff * progress)
);
}
return new SKColor(
ClampToByte(from.Red + redDiff * progress),
ClampToByte(from.Green + greenDiff * progress),
ClampToByte(from.Blue + blueDiff * progress),
ClampToByte(from.Alpha + alphaDiff * progress)
);
}
/// <summary>
/// Adds the two colors together
/// </summary>
/// <param name="a">The first color</param>
/// <param name="b">The second color</param>
/// <returns>The sum of the two colors</returns>
public static SKColor Sum(this SKColor a, SKColor b)
{
return new SKColor(
ClampToByte(a.Red + b.Red),
ClampToByte(a.Green + b.Green),
ClampToByte(a.Blue + b.Blue),
ClampToByte(a.Alpha + b.Alpha)
);
}
/// <summary>
/// Adds the two colors together
/// </summary>
/// <param name="a">The first color</param>
/// <param name="b">The second color</param>
/// <returns>The sum of the two colors</returns>
public static SKColor Sum(this SKColor a, SKColor b)
{
return new SKColor(
ClampToByte(a.Red + b.Red),
ClampToByte(a.Green + b.Green),
ClampToByte(a.Blue + b.Blue),
ClampToByte(a.Alpha + b.Alpha)
);
}
/// <summary>
/// Darkens the color by the specified amount
/// </summary>
/// <param name="c">The color to darken</param>
/// <param name="amount">The brightness of the new color</param>
/// <returns>The darkened color</returns>
public static SKColor Darken(this SKColor c, float amount)
{
c.ToHsl(out float h, out float s, out float l);
l *= 1f - amount;
return SKColor.FromHsl(h, s, l);
}
/// <summary>
/// Darkens the color by the specified amount
/// </summary>
/// <param name="c">The color to darken</param>
/// <param name="amount">The brightness of the new color</param>
/// <returns>The darkened color</returns>
public static SKColor Darken(this SKColor c, float amount)
{
c.ToHsl(out float h, out float s, out float l);
l *= 1f - amount;
return SKColor.FromHsl(h, s, l);
}
private static byte ClampToByte(float value)
{
return (byte) Math.Clamp(value, 0, 255);
}
private static byte ClampToByte(float value)
{
return (byte) Math.Clamp(value, 0, 255);
}
}
@@ -1,16 +1,15 @@
using SkiaSharp;
namespace Artemis.Core
namespace Artemis.Core;
internal static class SKPaintExtensions
{
internal static class SKPaintExtensions
internal static void DisposeSelfAndProperties(this SKPaint paint)
{
internal static void DisposeSelfAndProperties(this SKPaint paint)
{
paint.ImageFilter?.Dispose();
paint.ColorFilter?.Dispose();
paint.MaskFilter?.Dispose();
paint.Shader?.Dispose();
paint.Dispose();
}
paint.ImageFilter?.Dispose();
paint.ColorFilter?.Dispose();
paint.MaskFilter?.Dispose();
paint.Shader?.Dispose();
paint.Dispose();
}
}
+89 -91
View File
@@ -25,110 +25,108 @@
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace Artemis.Core
namespace Artemis.Core;
internal static class StreamExtensions
{
internal static class StreamExtensions
private const int DefaultBufferSize = 81920;
/// <summary>
/// Copies a stream to another stream
/// </summary>
/// <param name="source">The source <see cref="Stream" /> to copy from</param>
/// <param name="sourceLength">The length of the source stream, if known - used for progress reporting</param>
/// <param name="destination">The destination <see cref="Stream" /> to copy to</param>
/// <param name="bufferSize">The size of the copy block buffer</param>
/// <param name="progress">An <see cref="IProgress{T}" /> implementation for reporting progress</param>
/// <param name="cancellationToken">A cancellation token</param>
/// <returns>A task representing the operation</returns>
public static async Task CopyToAsync(
this Stream source,
long sourceLength,
Stream destination,
int bufferSize,
IProgress<(long, long)> progress,
CancellationToken cancellationToken)
{
private const int DefaultBufferSize = 81920;
if (source == null)
throw new ArgumentNullException(nameof(source));
if (!source.CanRead)
throw new ArgumentException("Has to be readable", nameof(source));
if (destination == null)
throw new ArgumentNullException(nameof(destination));
if (!destination.CanWrite)
throw new ArgumentException("Has to be writable", nameof(destination));
if (bufferSize <= 0)
bufferSize = DefaultBufferSize;
/// <summary>
/// Copies a stream to another stream
/// </summary>
/// <param name="source">The source <see cref="Stream" /> to copy from</param>
/// <param name="sourceLength">The length of the source stream, if known - used for progress reporting</param>
/// <param name="destination">The destination <see cref="Stream" /> to copy to</param>
/// <param name="bufferSize">The size of the copy block buffer</param>
/// <param name="progress">An <see cref="IProgress{T}" /> implementation for reporting progress</param>
/// <param name="cancellationToken">A cancellation token</param>
/// <returns>A task representing the operation</returns>
public static async Task CopyToAsync(
this Stream source,
long sourceLength,
Stream destination,
int bufferSize,
IProgress<(long, long)> progress,
CancellationToken cancellationToken)
byte[] buffer = new byte[bufferSize];
long totalBytesRead = 0;
int bytesRead;
while ((bytesRead = await source.ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false)) != 0)
{
if (source == null)
throw new ArgumentNullException(nameof(source));
if (!source.CanRead)
throw new ArgumentException("Has to be readable", nameof(source));
if (destination == null)
throw new ArgumentNullException(nameof(destination));
if (!destination.CanWrite)
throw new ArgumentException("Has to be writable", nameof(destination));
if (bufferSize <= 0)
bufferSize = DefaultBufferSize;
byte[] buffer = new byte[bufferSize];
long totalBytesRead = 0;
int bytesRead;
while ((bytesRead = await source.ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false)) != 0)
{
await destination.WriteAsync(buffer, 0, bytesRead, cancellationToken).ConfigureAwait(false);
totalBytesRead += bytesRead;
progress?.Report((totalBytesRead, sourceLength));
}
await destination.WriteAsync(buffer, 0, bytesRead, cancellationToken).ConfigureAwait(false);
totalBytesRead += bytesRead;
progress?.Report((totalBytesRead, sourceLength));
cancellationToken.ThrowIfCancellationRequested();
}
/// <summary>
/// Copies a stream to another stream
/// </summary>
/// <param name="source">The source <see cref="Stream" /> to copy from</param>
/// <param name="sourceLength">The length of the source stream, if known - used for progress reporting</param>
/// <param name="destination">The destination <see cref="Stream" /> to copy to</param>
/// <param name="progress">An <see cref="IProgress{T}" /> implementation for reporting progress</param>
/// <param name="cancellationToken">A cancellation token</param>
/// <returns>A task representing the operation</returns>
public static Task CopyToAsync(this Stream source, long sourceLength, Stream destination, IProgress<(long, long)> progress, CancellationToken cancellationToken)
{
return CopyToAsync(source, sourceLength, destination, 0, progress, cancellationToken);
}
progress?.Report((totalBytesRead, sourceLength));
cancellationToken.ThrowIfCancellationRequested();
}
/// <summary>
/// Copies a stream to another stream
/// </summary>
/// <param name="source">The source <see cref="Stream" /> to copy from</param>
/// <param name="destination">The destination <see cref="Stream" /> to copy to</param>
/// <param name="progress">An <see cref="IProgress{T}" /> implementation for reporting progress</param>
/// <param name="cancellationToken">A cancellation token</param>
/// <returns>A task representing the operation</returns>
public static Task CopyToAsync(this Stream source, Stream destination, IProgress<(long, long)> progress, CancellationToken cancellationToken)
{
return CopyToAsync(source, 0L, destination, 0, progress, cancellationToken);
}
/// <summary>
/// Copies a stream to another stream
/// </summary>
/// <param name="source">The source <see cref="Stream" /> to copy from</param>
/// <param name="sourceLength">The length of the source stream, if known - used for progress reporting</param>
/// <param name="destination">The destination <see cref="Stream" /> to copy to</param>
/// <param name="progress">An <see cref="IProgress{T}" /> implementation for reporting progress</param>
/// <param name="cancellationToken">A cancellation token</param>
/// <returns>A task representing the operation</returns>
public static Task CopyToAsync(this Stream source, long sourceLength, Stream destination, IProgress<(long, long)> progress, CancellationToken cancellationToken)
{
return CopyToAsync(source, sourceLength, destination, 0, progress, cancellationToken);
}
/// <summary>
/// Copies a stream to another stream
/// </summary>
/// <param name="source">The source <see cref="Stream" /> to copy from</param>
/// <param name="sourceLength">The length of the source stream, if known - used for progress reporting</param>
/// <param name="destination">The destination <see cref="Stream" /> to copy to</param>
/// <param name="progress">An <see cref="IProgress{T}" /> implementation for reporting progress</param>
/// <returns>A task representing the operation</returns>
public static Task CopyToAsync(this Stream source, long sourceLength, Stream destination, IProgress<(long, long)> progress)
{
return CopyToAsync(source, sourceLength, destination, 0, progress, default);
}
/// <summary>
/// Copies a stream to another stream
/// </summary>
/// <param name="source">The source <see cref="Stream" /> to copy from</param>
/// <param name="destination">The destination <see cref="Stream" /> to copy to</param>
/// <param name="progress">An <see cref="IProgress{T}" /> implementation for reporting progress</param>
/// <param name="cancellationToken">A cancellation token</param>
/// <returns>A task representing the operation</returns>
public static Task CopyToAsync(this Stream source, Stream destination, IProgress<(long, long)> progress, CancellationToken cancellationToken)
{
return CopyToAsync(source, 0L, destination, 0, progress, cancellationToken);
}
/// <summary>
/// Copies a stream to another stream
/// </summary>
/// <param name="source">The source <see cref="Stream" /> to copy from</param>
/// <param name="destination">The destination <see cref="Stream" /> to copy to</param>
/// <param name="progress">An <see cref="IProgress{T}" /> implementation for reporting progress</param>
/// <returns>A task representing the operation</returns>
public static Task CopyToAsync(this Stream source, Stream destination, IProgress<(long, long)> progress)
{
return CopyToAsync(source, 0L, destination, 0, progress, default);
}
/// <summary>
/// Copies a stream to another stream
/// </summary>
/// <param name="source">The source <see cref="Stream" /> to copy from</param>
/// <param name="sourceLength">The length of the source stream, if known - used for progress reporting</param>
/// <param name="destination">The destination <see cref="Stream" /> to copy to</param>
/// <param name="progress">An <see cref="IProgress{T}" /> implementation for reporting progress</param>
/// <returns>A task representing the operation</returns>
public static Task CopyToAsync(this Stream source, long sourceLength, Stream destination, IProgress<(long, long)> progress)
{
return CopyToAsync(source, sourceLength, destination, 0, progress, default);
}
/// <summary>
/// Copies a stream to another stream
/// </summary>
/// <param name="source">The source <see cref="Stream" /> to copy from</param>
/// <param name="destination">The destination <see cref="Stream" /> to copy to</param>
/// <param name="progress">An <see cref="IProgress{T}" /> implementation for reporting progress</param>
/// <returns>A task representing the operation</returns>
public static Task CopyToAsync(this Stream source, Stream destination, IProgress<(long, long)> progress)
{
return CopyToAsync(source, 0L, destination, 0, progress, default);
}
}
+224 -223
View File
@@ -5,249 +5,250 @@ using System.Linq;
using System.Reflection;
using Humanizer;
namespace Artemis.Core
namespace Artemis.Core;
/// <summary>
/// A static class providing <see cref="Type" /> extensions
/// </summary>
public static class TypeExtensions
{
/// <summary>
/// A static class providing <see cref="Type" /> extensions
/// </summary>
public static class TypeExtensions
private static readonly Dictionary<Type, List<Type>> PrimitiveTypeConversions = new()
{
private static readonly Dictionary<Type, List<Type>> PrimitiveTypeConversions = new()
{
{typeof(decimal), new List<Type> {typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(char)}},
{typeof(double), new List<Type> {typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(char), typeof(float)}},
{typeof(float), new List<Type> {typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(char), typeof(float)}},
{typeof(ulong), new List<Type> {typeof(byte), typeof(ushort), typeof(uint), typeof(char)}},
{typeof(long), new List<Type> {typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(char)}},
{typeof(uint), new List<Type> {typeof(byte), typeof(ushort), typeof(char)}},
{typeof(int), new List<Type> {typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(char)}},
{typeof(ushort), new List<Type> {typeof(byte), typeof(char)}},
{typeof(short), new List<Type> {typeof(byte)}}
};
{typeof(decimal), new List<Type> {typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(char)}},
{typeof(double), new List<Type> {typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(char), typeof(float)}},
{typeof(float), new List<Type> {typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(char), typeof(float)}},
{typeof(ulong), new List<Type> {typeof(byte), typeof(ushort), typeof(uint), typeof(char)}},
{typeof(long), new List<Type> {typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(char)}},
{typeof(uint), new List<Type> {typeof(byte), typeof(ushort), typeof(char)}},
{typeof(int), new List<Type> {typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(char)}},
{typeof(ushort), new List<Type> {typeof(byte), typeof(char)}},
{typeof(short), new List<Type> {typeof(byte)}}
};
private static readonly Dictionary<Type, string> TypeKeywords = new()
{
{typeof(bool), "bool"},
{typeof(byte), "byte"},
{typeof(sbyte), "sbyte"},
{typeof(char), "char"},
{typeof(decimal), "decimal"},
{typeof(double), "double"},
{typeof(float), "float"},
{typeof(int), "int"},
{typeof(uint), "uint"},
{typeof(long), "long"},
{typeof(ulong), "ulong"},
{typeof(short), "short"},
{typeof(ushort), "ushort"},
{typeof(object), "object"},
{typeof(string), "string"}
};
private static readonly Dictionary<Type, string> TypeKeywords = new()
{
{typeof(bool), "bool"},
{typeof(byte), "byte"},
{typeof(sbyte), "sbyte"},
{typeof(char), "char"},
{typeof(decimal), "decimal"},
{typeof(double), "double"},
{typeof(float), "float"},
{typeof(int), "int"},
{typeof(uint), "uint"},
{typeof(long), "long"},
{typeof(ulong), "ulong"},
{typeof(short), "short"},
{typeof(ushort), "ushort"},
{typeof(object), "object"},
{typeof(string), "string"}
};
/// <summary>
/// Determines whether the provided type is of a specified generic type
/// </summary>
/// <param name="type">The type to check</param>
/// <param name="genericType">The generic type to match</param>
/// <returns>True if the <paramref name="type" /> is generic and of generic type <paramref name="genericType" /></returns>
public static bool IsGenericType(this Type? type, Type genericType)
{
if (type == null)
return false;
/// <summary>
/// Determines whether the provided type is of a specified generic type
/// </summary>
/// <param name="type">The type to check</param>
/// <param name="genericType">The generic type to match</param>
/// <returns>True if the <paramref name="type" /> is generic and of generic type <paramref name="genericType" /></returns>
public static bool IsGenericType(this Type? type, Type genericType)
{
if (type == null)
return false;
return type.BaseType?.GetGenericTypeDefinition() == genericType;
}
return type.BaseType?.GetGenericTypeDefinition() == genericType;
}
/// <summary>
/// Determines whether the provided type is a struct
/// </summary>
/// <param name="type">The type to check</param>
/// <returns><see langword="true" /> if the type is a struct, otherwise <see langword="false" /></returns>
public static bool IsStruct(this Type type)
{
return type.IsValueType && !type.IsPrimitive && !type.IsEnum;
}
/// <summary>
/// Determines whether the provided type is a struct
/// </summary>
/// <param name="type">The type to check</param>
/// <returns><see langword="true" /> if the type is a struct, otherwise <see langword="false" /></returns>
public static bool IsStruct(this Type type)
{
return type.IsValueType && !type.IsPrimitive && !type.IsEnum;
}
/// <summary>
/// Determines whether the provided type is any kind of numeric type
/// </summary>
/// <param name="type">The type to check</param>
/// <returns><see langword="true" /> if the type a numeric type, otherwise <see langword="false" /></returns>
public static bool TypeIsNumber(this Type type)
{
return type == typeof(sbyte)
|| type == typeof(byte)
|| type == typeof(short)
|| type == typeof(ushort)
|| type == typeof(int)
|| type == typeof(uint)
|| type == typeof(long)
|| type == typeof(ulong)
|| type == typeof(float)
|| type == typeof(double)
|| type == typeof(decimal);
}
/// <summary>
/// Determines whether the provided type is any kind of numeric type
/// </summary>
/// <param name="type">The type to check</param>
/// <returns><see langword="true" /> if the type a numeric type, otherwise <see langword="false" /></returns>
public static bool TypeIsNumber(this Type type)
{
return type == typeof(sbyte)
|| type == typeof(byte)
|| type == typeof(short)
|| type == typeof(ushort)
|| type == typeof(int)
|| type == typeof(uint)
|| type == typeof(long)
|| type == typeof(ulong)
|| type == typeof(float)
|| type == typeof(double)
|| type == typeof(decimal);
}
/// <summary>
/// Determines whether the provided value is any kind of numeric type
/// </summary>
/// <param name="value">The value to check</param>
/// <returns><see langword="true" /> if the value is of a numeric type, otherwise <see langword="false" /></returns>
public static bool IsNumber([NotNullWhenAttribute(true)] this object? value)
{
return value is sbyte or byte or short or ushort or int or uint or long or ulong or float or double or decimal;
}
/// <summary>
/// Determines whether the provided value is any kind of numeric type
/// </summary>
/// <param name="value">The value to check</param>
/// <returns><see langword="true" /> if the value is of a numeric type, otherwise <see langword="false" /></returns>
public static bool IsNumber([NotNullWhenAttribute(true)] this object? value)
{
return value is sbyte or byte or short or ushort or int or uint or long or ulong or float or double or decimal;
}
// From https://stackoverflow.com/a/2224421/5015269 but inverted and renamed to match similar framework methods
/// <summary>
/// Determines whether an instance of a specified type can be casted to a variable of the current type
/// </summary>
/// <returns></returns>
public static bool IsCastableFrom(this Type to, Type from)
{
if (to.TypeIsNumber() && from.TypeIsNumber())
return true;
if (to.IsAssignableFrom(from))
return true;
if (PrimitiveTypeConversions.ContainsKey(to) && PrimitiveTypeConversions[to].Contains(from))
return true;
bool castable = from.GetMethods(BindingFlags.Public | BindingFlags.Static)
.Any(m => m.ReturnType == to && (m.Name == "op_Implicit" || m.Name == "op_Explicit"));
return castable;
}
// From https://stackoverflow.com/a/2224421/5015269 but inverted and renamed to match similar framework methods
/// <summary>
/// Determines whether an instance of a specified type can be casted to a variable of the current type
/// </summary>
/// <returns></returns>
public static bool IsCastableFrom(this Type to, Type from)
{
if (to.TypeIsNumber() && from.TypeIsNumber())
return true;
if (to.IsAssignableFrom(from))
return true;
if (PrimitiveTypeConversions.ContainsKey(to) && PrimitiveTypeConversions[to].Contains(from))
return true;
bool castable = from.GetMethods(BindingFlags.Public | BindingFlags.Static)
.Any(m => m.ReturnType == to && (m.Name == "op_Implicit" || m.Name == "op_Explicit"));
return castable;
}
/// <summary>
/// Scores how well the two types can be casted from one to another, 5 being a perfect match and 0 being not castable
/// at all
/// </summary>
/// <returns></returns>
public static int ScoreCastability(this Type to, Type? from)
{
if (from == null)
return 0;
if (to == from)
return 5;
if (to.TypeIsNumber() && from.TypeIsNumber())
return 4;
if (PrimitiveTypeConversions.ContainsKey(to) && PrimitiveTypeConversions[to].Contains(from))
return 3;
bool castable = from.GetMethods(BindingFlags.Public | BindingFlags.Static)
.Any(m => m.ReturnType == to && (m.Name == "op_Implicit" || m.Name == "op_Explicit"));
if (castable)
return 2;
if (to.IsAssignableFrom(from))
return 1;
/// <summary>
/// Scores how well the two types can be casted from one to another, 5 being a perfect match and 0 being not castable
/// at all
/// </summary>
/// <returns></returns>
public static int ScoreCastability(this Type to, Type? from)
{
if (from == null)
return 0;
if (to == from)
return 5;
if (to.TypeIsNumber() && from.TypeIsNumber())
return 4;
if (PrimitiveTypeConversions.ContainsKey(to) && PrimitiveTypeConversions[to].Contains(from))
return 3;
bool castable = from.GetMethods(BindingFlags.Public | BindingFlags.Static)
.Any(m => m.ReturnType == to && (m.Name == "op_Implicit" || m.Name == "op_Explicit"));
if (castable)
return 2;
if (to.IsAssignableFrom(from))
return 1;
return 0;
}
/// <summary>
/// Returns the default value of the given type
/// </summary>
public static object? GetDefault(this Type type)
{
return type.IsValueType ? Activator.CreateInstance(type) : null;
}
/// <summary>
/// Determines whether the given type is a generic enumerable
/// </summary>
public static bool IsGenericEnumerable(this Type type)
{
// String is an IEnumerable to be fair, but not for us
if (type == typeof(string))
return false;
// It may actually be one instead of implementing one ;)
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IEnumerable<>))
return true;
return type.GetInterfaces().Any(x =>
x.IsGenericType &&
x.GetGenericTypeDefinition() == typeof(IEnumerable<>));
}
/// <summary>
/// Determines the type of the provided generic enumerable type
/// </summary>
public static Type? GetGenericEnumerableType(this Type type)
{
// It may actually be one instead of implementing one ;)
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IEnumerable<>))
return type.GenericTypeArguments[0];
Type? enumerableType = type.GetInterfaces().FirstOrDefault(x =>
x.IsGenericType &&
x.GetGenericTypeDefinition() == typeof(IEnumerable<>));
return enumerableType?.GenericTypeArguments[0];
}
/// <summary>
/// Determines if the <paramref name="typeToCheck"></paramref> is of a certain <paramref name="genericType" />.
/// </summary>
/// <param name="typeToCheck">The type to check.</param>
/// <param name="genericType">The generic type it should be or implement</param>
public static bool IsOfGenericType(this Type typeToCheck, Type genericType)
{
return typeToCheck.IsOfGenericType(genericType, out Type? _);
}
/// <summary>
/// Determines a display name for the given type
/// </summary>
/// <param name="type">The type to determine the name for</param>
/// <param name="humanize">Whether or not to humanize the result, defaults to false</param>
/// <returns></returns>
public static string GetDisplayName(this Type type, bool humanize = false)
{
if (!type.IsGenericType)
{
string displayValue = TypeKeywords.TryGetValue(type, out string? keyword) ? keyword! : type.Name;
return humanize ? displayValue.Humanize() : displayValue;
}
/// <summary>
/// Returns the default value of the given type
/// </summary>
public static object? GetDefault(this Type type)
{
return type.IsValueType ? Activator.CreateInstance(type) : null;
}
Type genericTypeDefinition = type.GetGenericTypeDefinition();
if (genericTypeDefinition == typeof(Nullable<>))
return type.GenericTypeArguments[0].GetDisplayName(humanize) + "?";
/// <summary>
/// Determines whether the given type is a generic enumerable
/// </summary>
public static bool IsGenericEnumerable(this Type type)
string stripped = genericTypeDefinition.Name.Split('`')[0];
return $"{stripped}<{string.Join(", ", type.GenericTypeArguments.Select(t => t.GetDisplayName(humanize)))}>";
}
private static bool IsOfGenericType(this Type? typeToCheck, Type genericType, out Type? concreteGenericType)
{
while (true)
{
// String is an IEnumerable to be fair, but not for us
if (type == typeof(string))
concreteGenericType = null;
if (genericType == null)
throw new ArgumentNullException(nameof(genericType));
if (!genericType.IsGenericTypeDefinition)
throw new ArgumentException("The definition needs to be a GenericTypeDefinition", nameof(genericType));
if (typeToCheck == null || typeToCheck == typeof(object))
return false;
// It may actually be one instead of implementing one ;)
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IEnumerable<>))
if (typeToCheck == genericType)
{
concreteGenericType = typeToCheck;
return true;
return type.GetInterfaces().Any(x =>
x.IsGenericType &&
x.GetGenericTypeDefinition() == typeof(IEnumerable<>));
}
/// <summary>
/// Determines the type of the provided generic enumerable type
/// </summary>
public static Type? GetGenericEnumerableType(this Type type)
{
// It may actually be one instead of implementing one ;)
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IEnumerable<>))
return type.GenericTypeArguments[0];
Type? enumerableType = type.GetInterfaces().FirstOrDefault(x =>
x.IsGenericType &&
x.GetGenericTypeDefinition() == typeof(IEnumerable<>));
return enumerableType?.GenericTypeArguments[0];
}
/// <summary>
/// Determines if the <paramref name="typeToCheck"></paramref> is of a certain <paramref name="genericType"/>.
/// </summary>
/// <param name="typeToCheck">The type to check.</param>
/// <param name="genericType">The generic type it should be or implement</param>
public static bool IsOfGenericType(this Type typeToCheck, Type genericType)
{
return typeToCheck.IsOfGenericType(genericType, out Type? _);
}
private static bool IsOfGenericType(this Type? typeToCheck, Type genericType, out Type? concreteGenericType)
{
while (true)
{
concreteGenericType = null;
if (genericType == null)
throw new ArgumentNullException(nameof(genericType));
if (!genericType.IsGenericTypeDefinition)
throw new ArgumentException("The definition needs to be a GenericTypeDefinition", nameof(genericType));
if (typeToCheck == null || typeToCheck == typeof(object))
return false;
if (typeToCheck == genericType)
{
concreteGenericType = typeToCheck;
return true;
}
if ((typeToCheck.IsGenericType ? typeToCheck.GetGenericTypeDefinition() : typeToCheck) == genericType)
{
concreteGenericType = typeToCheck;
return true;
}
if (genericType.IsInterface)
foreach (Type i in typeToCheck.GetInterfaces())
if (i.IsOfGenericType(genericType, out concreteGenericType))
return true;
typeToCheck = typeToCheck.BaseType;
}
}
/// <summary>
/// Determines a display name for the given type
/// </summary>
/// <param name="type">The type to determine the name for</param>
/// <param name="humanize">Whether or not to humanize the result, defaults to false</param>
/// <returns></returns>
public static string GetDisplayName(this Type type, bool humanize = false)
{
if (!type.IsGenericType)
{
string displayValue = TypeKeywords.TryGetValue(type, out string? keyword) ? keyword! : type.Name;
return humanize ? displayValue.Humanize() : displayValue;
}
Type genericTypeDefinition = type.GetGenericTypeDefinition();
if (genericTypeDefinition == typeof(Nullable<>))
return type.GenericTypeArguments[0].GetDisplayName(humanize) + "?";
if ((typeToCheck.IsGenericType ? typeToCheck.GetGenericTypeDefinition() : typeToCheck) == genericType)
{
concreteGenericType = typeToCheck;
return true;
}
string stripped = genericTypeDefinition.Name.Split('`')[0];
return $"{stripped}<{string.Join(", ", type.GenericTypeArguments.Select(t => t.GetDisplayName(humanize)))}>";
if (genericType.IsInterface)
foreach (Type i in typeToCheck.GetInterfaces())
{
if (i.IsOfGenericType(genericType, out concreteGenericType))
return true;
}
typeToCheck = typeToCheck.BaseType;
}
}
}