You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Connected.Framework/Connected.Interop/Types.cs

226 lines
5.3 KiB

2 years ago
using System.Globalization;
using System.Reflection;
namespace Connected.Interop;
public static class Types
{
private static Func<Type, object>? _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<TypeInfo> 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<Type, object>)guo.CreateDelegate(typeof(Func<Type, object>)), 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<T>(this Type type)
{
return CreateInstance<T>(type, null);
}
public static T? CreateInstance<T>(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;
}
}