75 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			75 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
using System.Reflection;
 | 
						|
 | 
						|
namespace Syntriax.Engine.Serialization;
 | 
						|
 | 
						|
internal static class Utils
 | 
						|
{
 | 
						|
    internal static bool HasAttribute<T>(this MemberInfo memberInfo) where T : Attribute => memberInfo.GetCustomAttribute<T>() 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<FieldInfo> fieldInfos = GetFieldInfosIncludingBaseClasses(objectType, BindingFlags.Instance | BindingFlags.FlattenHierarchy | BindingFlags.NonPublic | BindingFlags.Public);
 | 
						|
 | 
						|
        List<PropertyInfo> propertyInfos = GetPropertyInfosIncludingBaseClasses(objectType, BindingFlags.Instance | BindingFlags.FlattenHierarchy | BindingFlags.Public)
 | 
						|
            .Where(pi => pi.SetMethod is not null)
 | 
						|
            .ToList();
 | 
						|
 | 
						|
        return new TypeData(fieldInfos, propertyInfos);
 | 
						|
    }
 | 
						|
 | 
						|
    internal static List<FieldInfo> GetFieldInfosIncludingBaseClasses(Type type, BindingFlags bindingFlags)
 | 
						|
    {
 | 
						|
        if (type.BaseType is null)
 | 
						|
            return [.. type.GetFields(bindingFlags)];
 | 
						|
 | 
						|
        Type currentType = type;
 | 
						|
        FieldInfoComparer fieldComparer = new();
 | 
						|
        HashSet<FieldInfo> 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<PropertyInfo> GetPropertyInfosIncludingBaseClasses(Type type, BindingFlags bindingFlags)
 | 
						|
    {
 | 
						|
        if (type.BaseType is null)
 | 
						|
            return [.. type.GetProperties(bindingFlags)];
 | 
						|
 | 
						|
        Type currentType = type;
 | 
						|
        PropertyInfoComparer propertyComparer = new();
 | 
						|
        HashSet<PropertyInfo> 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<FieldInfo>
 | 
						|
    {
 | 
						|
        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<PropertyInfo>
 | 
						|
    {
 | 
						|
        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<FieldInfo> Fields, IEnumerable<PropertyInfo> Properties)
 | 
						|
{
 | 
						|
    public static implicit operator (IEnumerable<FieldInfo> fields, IEnumerable<PropertyInfo> properties)(TypeData value) => (value.Fields, value.Properties);
 | 
						|
    public static implicit operator TypeData((IEnumerable<FieldInfo> fields, IEnumerable<PropertyInfo> properties) value) => new(value.fields, value.properties);
 | 
						|
}
 |