using System.Reflection; namespace Syntriax.Engine.Serialization; internal static class Utils { internal static bool HasAttribute(this MemberInfo memberInfo) where T : Attribute => memberInfo.GetCustomAttribute() is not null; internal static bool IsEnumerable(this Type type) => typeof(System.Collections.IEnumerable).IsAssignableFrom(type) && type != typeof(string); internal static TypeData GetTypeData(this Type objectType) { List eventInfos = objectType.GetEvents(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public) .OrderBy(ei => ei.Name) .ToList(); List fieldInfos = GetFieldInfosIncludingBaseClasses(objectType, BindingFlags.Instance | BindingFlags.FlattenHierarchy | BindingFlags.NonPublic | BindingFlags.Public) .Where(pi => !eventInfos.Any(ei => pi.Name.CompareTo(ei.Name) == 0)).ToList(); List propertyInfos = GetPropertyInfosIncludingBaseClasses(objectType, BindingFlags.Instance | BindingFlags.FlattenHierarchy | BindingFlags.Public) .Where(pi => pi.SetMethod is not null && !eventInfos.Any(ei => pi.Name.CompareTo(ei.Name) == 0)) .ToList(); return new TypeData(fieldInfos, propertyInfos); } internal static List GetFieldInfosIncludingBaseClasses(Type type, BindingFlags bindingFlags) { if (type.BaseType is null) return [.. type.GetFields(bindingFlags)]; Type currentType = type; FieldInfoComparer fieldComparer = new(); HashSet fieldInfoList = new(type.GetFields(bindingFlags), fieldComparer); while (currentType.BaseType is Type baseType) { currentType = baseType; fieldInfoList.UnionWith(currentType!.GetFields(bindingFlags)); } return [.. fieldInfoList.OrderBy(fi => fi.Name)]; } internal static List GetPropertyInfosIncludingBaseClasses(Type type, BindingFlags bindingFlags) { if (type.BaseType is null) return [.. type.GetProperties(bindingFlags)]; Type currentType = type; PropertyInfoComparer propertyComparer = new(); HashSet propertyInfoList = new(type.GetProperties(bindingFlags), propertyComparer); while (currentType.BaseType is Type baseType) { currentType = baseType; propertyInfoList.UnionWith(currentType.GetProperties(bindingFlags)); } return [.. propertyInfoList.OrderBy(pi => pi.Name)]; } private class FieldInfoComparer : IEqualityComparer { public bool Equals(FieldInfo? x, FieldInfo? y) => x?.DeclaringType == y?.DeclaringType && x?.Name == y?.Name; public int GetHashCode(FieldInfo obj) => obj.Name.GetHashCode() ^ obj.DeclaringType!.GetHashCode(); } private class PropertyInfoComparer : IEqualityComparer { public bool Equals(PropertyInfo? x, PropertyInfo? y) => x?.DeclaringType == y?.DeclaringType && x?.Name == y?.Name; public int GetHashCode(PropertyInfo obj) => obj.Name.GetHashCode() ^ obj.DeclaringType!.GetHashCode(); } } internal record struct TypeData(IEnumerable Fields, IEnumerable Properties) { public static implicit operator (IEnumerable fields, IEnumerable properties)(TypeData value) => (value.Fields, value.Properties); public static implicit operator TypeData((IEnumerable fields, IEnumerable properties) value) => new(value.fields, value.properties); }