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.
226 lines
5.3 KiB
226 lines
5.3 KiB
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;
|
|
}
|
|
}
|