123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179 |
- using System.Collections.Concurrent;
- using System.Diagnostics.CodeAnalysis;
- using System.Linq;
- using System.Reflection;
- using System.Runtime.CompilerServices;
- using Jint.Native;
- using Jint.Runtime;
- namespace Jint.Extensions;
- internal static class ReflectionExtensions
- {
- private static readonly Type nullableType = typeof(Nullable<>);
- internal static void SetValue(this MemberInfo memberInfo, object forObject, object? value)
- {
- if (memberInfo.MemberType == MemberTypes.Field)
- {
- var fieldInfo = (FieldInfo) memberInfo;
- if (value != null && fieldInfo.FieldType.IsInstanceOfType(value))
- {
- fieldInfo.SetValue(forObject, value);
- }
- }
- else if (memberInfo.MemberType == MemberTypes.Property)
- {
- var propertyInfo = (PropertyInfo) memberInfo;
- if (value != null && propertyInfo.PropertyType.IsInstanceOfType(value))
- {
- propertyInfo.SetValue(forObject, value);
- }
- }
- }
- internal static Type GetDefinedType(this MemberInfo memberInfo)
- {
- return memberInfo switch
- {
- PropertyInfo propertyInfo => propertyInfo.PropertyType,
- FieldInfo fieldInfo => fieldInfo.FieldType,
- _ => null!
- };
- }
- internal static IEnumerable<MethodInfo> GetExtensionMethods([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] this Type type)
- {
- return type.GetMethods(BindingFlags.Public | BindingFlags.Static)
- .Where(static m => m.IsExtensionMethod());
- }
- private static readonly ConcurrentDictionary<Type, List<MethodInfo>> _operatorOverloadMethodCache = new();
- internal static List<MethodInfo> GetOperatorOverloadMethods([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] this Type type)
- {
- return _operatorOverloadMethodCache.GetOrAdd(type, static t =>
- {
- #pragma warning disable IL2070
- return t.GetMethods(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy)
- .Where(static m => m.IsSpecialName)
- .ToList();
- #pragma warning restore IL2070
- });
- }
- private static bool IsExtensionMethod(this MethodBase methodInfo)
- {
- return methodInfo.IsDefined(typeof(ExtensionAttribute), inherit: true);
- }
- public static bool IsNullable(this Type type)
- {
- return type is { IsGenericType: true } && type.GetGenericTypeDefinition() == nullableType;
- }
- public static bool IsNumeric(this Type type)
- {
- if (type == null || type.IsEnum)
- {
- return false;
- }
- switch (Type.GetTypeCode(type))
- {
- case TypeCode.Byte:
- case TypeCode.Decimal:
- case TypeCode.Double:
- case TypeCode.Int16:
- case TypeCode.Int32:
- case TypeCode.Int64:
- case TypeCode.SByte:
- case TypeCode.Single:
- case TypeCode.UInt16:
- case TypeCode.UInt32:
- case TypeCode.UInt64:
- return true;
- default:
- return false;
- }
- }
- public static bool IsClrNumericCoercible(this Type type)
- {
- if (type == null || type.IsEnum)
- {
- return false;
- }
- switch (Type.GetTypeCode(type))
- {
- case TypeCode.Decimal:
- case TypeCode.Double:
- case TypeCode.Int32:
- case TypeCode.Int64:
- return true;
- default:
- return false;
- }
- }
- public static object AsNumberOfType(this double d, TypeCode type)
- {
- switch (type)
- {
- case TypeCode.Decimal:
- return (decimal) d;
- case TypeCode.Double:
- return d;
- case TypeCode.Int32:
- return (int) d;
- case TypeCode.Int64:
- return (long) d;
- default:
- Throw.ArgumentException("Cannot convert " + type);
- return null;
- }
- }
- public static bool TryConvertViaTypeCoercion(
- Type? memberType,
- ValueCoercionType valueCoercionType,
- JsValue value,
- [NotNullWhen(true)] out object? converted)
- {
- if (value.IsInteger() && (memberType == typeof(int) || memberType == typeof(long)))
- {
- // safe and doesn't require configuration
- converted = value.AsInteger();
- return true;
- }
- if (memberType == typeof(bool) && (valueCoercionType & ValueCoercionType.Boolean) != ValueCoercionType.None)
- {
- converted = TypeConverter.ToBoolean(value);
- return true;
- }
- if (memberType == typeof(string)
- && !value.IsNullOrUndefined()
- && (valueCoercionType & ValueCoercionType.String) != ValueCoercionType.None)
- {
- // we know how to print out correct string presentation for primitives
- // that are non-null and non-undefined
- converted = TypeConverter.ToString(value);
- return true;
- }
- if (memberType is not null && memberType.IsClrNumericCoercible() && (valueCoercionType & ValueCoercionType.Number) != ValueCoercionType.None)
- {
- // we know how to print out correct string presentation for primitives
- // that are non-null and non-undefined
- var number = TypeConverter.ToNumber(value);
- converted = number.AsNumberOfType(Type.GetTypeCode(memberType));
- return true;
- }
- converted = null;
- return false;
- }
- }
|