using System.Globalization; using System.Reflection; namespace Connected.Interop; public static class Types { private static Func? _getUninitializedObject; public static bool IsAssignableFrom(this Type type, Type otherType) { return type.GetTypeInfo().IsAssignableFrom(otherType.GetTypeInfo()); } public static ConstructorInfo? FindConstructor(this Type type, Type[] parameterTypes) { foreach (var constructor in type.GetTypeInfo().DeclaredConstructors) { if (Methods.ParametersMatch(constructor.GetParameters(), parameterTypes)) return constructor; } return default; } private static bool TypesMatch(Type[] a, Type[] b) { if (a.Length != b.Length) return false; for (var i = 0; i < a.Length; i++) { if (a[i] != b[i]) return false; } return true; } public static IEnumerable GetInheritedTypeInfos(this Type type) { var info = type.GetTypeInfo(); yield return info; if (info.IsInterface) { foreach (var ii in info.ImplementedInterfaces) { foreach (var iface in ii.GetInheritedTypeInfos()) yield return iface; } } else { for (var i = info.BaseType?.GetTypeInfo(); i != null; i = i.BaseType?.GetTypeInfo()) yield return i; } } public static object GetUninitializedObject(this Type type) { if (_getUninitializedObject is null) { var a = typeof(System.Runtime.CompilerServices.RuntimeHelpers).GetTypeInfo().Assembly; var fs = a.DefinedTypes.FirstOrDefault(t => string.Equals(t.FullName, "System.Runtime.Serialization.FormatterServices")); var guo = fs?.DeclaredMethods.FirstOrDefault(m => m.Name == nameof(GetUninitializedObject)); if (guo is null) throw new NotSupportedException($"The runtime does not support the '{nameof(GetUninitializedObject)}' API."); Interlocked.CompareExchange(ref _getUninitializedObject, (Func)guo.CreateDelegate(typeof(Func)), null); } return type.GetUninitializedObject(); } public static bool IsTypePrimitive(this Type type) { if (type == null) return false; return type.IsPrimitive || type == typeof(string) || type == typeof(decimal) || type.IsEnum || type.IsValueType; } public static bool IsNumber(this Type type) { return type == typeof(byte) || type == typeof(sbyte) || 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); } public static string ShortName(this Type type) { var r = type.Name; if (r.Contains('.')) r = r.Substring(r.LastIndexOf('.') + 1); return r; } public static object? CreateInstance(this Type type) { return CreateInstance(type, null); } public static object? CreateInstance(this Type type, object[]? ctorArgs) { if (type is null) return default; object? instance; if (ctorArgs is null) instance = CreateInstanceInternal(type); else instance = CreateInstanceInternal(type, BindingFlags.CreateInstance, ctorArgs); return instance; } public static T? CreateInstance(this Type type) { return CreateInstance(type, null); } public static T? CreateInstance(this Type type, object[]? ctorArgs) { if (type is null) return default; object? instance = null; if (ctorArgs is null) instance = CreateInstanceInternal(type); else instance = CreateInstanceInternal(type, BindingFlags.CreateInstance, ctorArgs); if (instance is null) throw new SysException(nameof(Types), $"{SR.ErrInvalidInterface} ({typeof(T).Name})"); if (TypeConversion.TryConvert(instance, out T? result)) return result; return default; } private static object? CreateInstanceInternal(this Type type) { if (type.IsTypePrimitive()) return type.GetDefault(); return Activator.CreateInstance(type); } private static object? CreateInstanceInternal(this Type type, BindingFlags bindingFlags, object[] ctorArgs) { if (type.IsTypePrimitive()) return type.GetDefault(); return Activator.CreateInstance(type, bindingFlags, null, ctorArgs, CultureInfo.InvariantCulture); } public static object? GetDefault(this Type type) { if (type is null || type == typeof(void)) return default; var isNullable = !type.GetTypeInfo().IsValueType || type.IsNullableType(); if (isNullable) return default; if (type.ContainsGenericParameters) throw new SysException(nameof(Types), $"{MethodBase.GetCurrentMethod()} {SR.ErrDefaultGeneric} ({type})"); return Activator.CreateInstance(type); } public static Type ResolveInterface(object component, string method, params Type[] parameters) { var itfs = component.GetType().GetInterfaces(); foreach (var i in itfs) { var methods = i.GetMethods(BindingFlags.Public | BindingFlags.Instance).Where(f => string.Equals(f.Name, method, StringComparison.Ordinal)); foreach (var m in methods) { var pars = m.GetParameters(); if (pars.Length != parameters.Length) continue; var parametersMatch = true; for (var j = 0; j < parameters.Length; j++) { if (pars[j].ParameterType != parameters[j] && !parameters[j].IsAssignableFrom(pars[j].ParameterType)) { parametersMatch = false; break; } } if (parametersMatch) return i; } } return null; } }