using System.Reflection; namespace Just.Railway; internal static class ReflectionHelper { [Pure, MethodImpl(MethodImplOptions.AggressiveInlining)] public static R ObjectCast(object value) where R: class => (R)value; [Pure, MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsEqual(T? left, T? right) => TypeReflectionCache.IsEqualFunc(left, right); [Pure, MethodImpl(MethodImplOptions.AggressiveInlining)] /// /// Test for potential nullability /// /// true if T is reference type or Nullable value type. public static bool IsNullable() => TypeReflectionCache.IsNullable; [Pure, MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNullableStruct() => TypeReflectionCache.IsNullableStruct; private static class TypeReflectionCache { public static readonly Func IsEqualFunc; static TypeReflectionCache() { var type = typeof(T); var isNullableStruct = type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>); var underlyingType = isNullableStruct ? type.GenericTypeArguments.First() : type; var thisType = typeof(TypeReflectionCache); var equatableType = typeof(IEquatable<>).MakeGenericType(underlyingType); if (equatableType.IsAssignableFrom(underlyingType)) { var isEqualFunc = thisType.GetMethod(isNullableStruct ? nameof(IsEqualNullable) : nameof(IsEqual), BindingFlags.Static | BindingFlags.Public) !.MakeGenericMethod(underlyingType); IsEqualFunc = (Func)Delegate.CreateDelegate(typeof(Func), isEqualFunc); } else { IsEqualFunc = static (left, right) => left is null ? right is null : left.Equals(right); } IsNullableStruct = isNullableStruct; IsNullable = isNullableStruct || !type.IsValueType; } public static bool IsNullable { get; } public static bool IsNullableStruct { get; } #pragma warning disable CS8604 // Possible null reference argument. [Pure] public static bool IsEqual(R? left, R? right) where R : notnull, IEquatable, T => left is null ? right is null : left.Equals(right); [Pure] public static bool IsEqualNullable(R? left, R? right) where R : struct, IEquatable => left is null ? right is null : right is not null && left.Value.Equals(right.Value); #pragma warning restore CS8604 // Possible null reference argument. } }