158 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			158 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
using System;
 | 
						|
using System.Collections.Generic;
 | 
						|
using System.Reflection;
 | 
						|
 | 
						|
using Engine.Core.Factory;
 | 
						|
 | 
						|
namespace Engine.Core.Serialization;
 | 
						|
 | 
						|
public class SerializedClass
 | 
						|
{
 | 
						|
    private const BindingFlags PRIVATE_BINDING_FLAGS = BindingFlags.Instance | BindingFlags.NonPublic;
 | 
						|
    private const BindingFlags PUBLIC_BINDING_FLAGS = BindingFlags.Instance | BindingFlags.Public;
 | 
						|
 | 
						|
    public string Type { get; set; } = string.Empty;
 | 
						|
    public Dictionary<string, object?> Public { get; set; } = [];
 | 
						|
    public Dictionary<string, object?> Private { get; set; } = [];
 | 
						|
 | 
						|
    public SerializedClass() { }
 | 
						|
    public SerializedClass(object @class)
 | 
						|
    {
 | 
						|
        UpdateClass(@class);
 | 
						|
    }
 | 
						|
 | 
						|
    private void UpdateClass(object @class)
 | 
						|
    {
 | 
						|
        Type type = @class.GetType();
 | 
						|
        Type = type.FullName ?? type.Name;
 | 
						|
 | 
						|
        bool shouldSerializeAll = type.HasAttribute<SerializeAllAttribute>();
 | 
						|
 | 
						|
        Public.Clear();
 | 
						|
        Private.Clear();
 | 
						|
 | 
						|
        foreach (PropertyInfo privatePropertyInfo in Utils.GetPropertyInfosIncludingBaseClasses(type, PRIVATE_BINDING_FLAGS))
 | 
						|
        {
 | 
						|
            if (privatePropertyInfo.HasAttribute<IgnoreSerializationAttribute>())
 | 
						|
                continue;
 | 
						|
 | 
						|
            if (privatePropertyInfo.SetMethod is null)
 | 
						|
                continue;
 | 
						|
 | 
						|
            if (!shouldSerializeAll && !privatePropertyInfo.HasAttribute<SerializeAttribute>())
 | 
						|
                continue;
 | 
						|
 | 
						|
            object? value = privatePropertyInfo.GetValue(@class);
 | 
						|
            if (value is IIdentifiable identifiable)
 | 
						|
                Private.Add(privatePropertyInfo.Name, identifiable.Id);
 | 
						|
            else
 | 
						|
                Private.Add(privatePropertyInfo.Name, value);
 | 
						|
        }
 | 
						|
 | 
						|
        foreach (PropertyInfo publicPropertyInfo in Utils.GetPropertyInfosIncludingBaseClasses(type, PUBLIC_BINDING_FLAGS))
 | 
						|
        {
 | 
						|
            if (publicPropertyInfo.HasAttribute<IgnoreSerializationAttribute>())
 | 
						|
                continue;
 | 
						|
 | 
						|
            if (publicPropertyInfo.SetMethod is null)
 | 
						|
                continue;
 | 
						|
 | 
						|
            if (!shouldSerializeAll && !publicPropertyInfo.HasAttribute<SerializeAttribute>())
 | 
						|
                continue;
 | 
						|
 | 
						|
            object? value = publicPropertyInfo.GetValue(@class);
 | 
						|
            if (value is IIdentifiable identifiable)
 | 
						|
                Public.Add(publicPropertyInfo.Name, identifiable.Id);
 | 
						|
            else
 | 
						|
                Public.Add(publicPropertyInfo.Name, value);
 | 
						|
        }
 | 
						|
 | 
						|
        foreach (FieldInfo privateFieldInfo in Utils.GetFieldInfosIncludingBaseClasses(type, PRIVATE_BINDING_FLAGS))
 | 
						|
        {
 | 
						|
            if (privateFieldInfo.HasAttribute<System.Runtime.CompilerServices.CompilerGeneratedAttribute>())
 | 
						|
                continue;
 | 
						|
 | 
						|
            if (!shouldSerializeAll && !privateFieldInfo.HasAttribute<SerializeAttribute>())
 | 
						|
                continue;
 | 
						|
 | 
						|
            object? value = privateFieldInfo.GetValue(@class);
 | 
						|
            if (value is IIdentifiable identifiable)
 | 
						|
                Private.Add(privateFieldInfo.Name, identifiable.Id);
 | 
						|
            else
 | 
						|
                Private.Add(privateFieldInfo.Name, value);
 | 
						|
        }
 | 
						|
 | 
						|
        foreach (FieldInfo publicFieldInfo in Utils.GetFieldInfosIncludingBaseClasses(type, PUBLIC_BINDING_FLAGS))
 | 
						|
        {
 | 
						|
            if (publicFieldInfo.HasAttribute<System.Runtime.CompilerServices.CompilerGeneratedAttribute>())
 | 
						|
                continue;
 | 
						|
 | 
						|
            if (!shouldSerializeAll && !publicFieldInfo.HasAttribute<SerializeAttribute>())
 | 
						|
                continue;
 | 
						|
 | 
						|
            object? value = publicFieldInfo.GetValue(@class);
 | 
						|
            if (value is IIdentifiable identifiable)
 | 
						|
                Public.Add(publicFieldInfo.Name, identifiable.Id);
 | 
						|
            else
 | 
						|
                Public.Add(publicFieldInfo.Name, value);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    public object CreateInstance()
 | 
						|
    {
 | 
						|
        Type type = TypeFactory.GetType(Type);
 | 
						|
        object instance = TypeFactory.Get(type);
 | 
						|
 | 
						|
        foreach ((string key, object? value) in Private)
 | 
						|
            AssignVariable(key, type, instance, value, PRIVATE_BINDING_FLAGS);
 | 
						|
 | 
						|
        foreach ((string key, object? value) in Public)
 | 
						|
            AssignVariable(key, type, instance, value, PUBLIC_BINDING_FLAGS);
 | 
						|
 | 
						|
        return instance;
 | 
						|
    }
 | 
						|
 | 
						|
    public object CreateInstance(IdentifiableRegistry? identifiableRegistry)
 | 
						|
    {
 | 
						|
        if (identifiableRegistry is null)
 | 
						|
            return CreateInstance();
 | 
						|
 | 
						|
        Type type = TypeFactory.GetType(Type);
 | 
						|
        object instance = TypeFactory.Get(type);
 | 
						|
 | 
						|
        foreach ((string key, object? value) in Private)
 | 
						|
            AssignVariable(key, type, instance, value, PRIVATE_BINDING_FLAGS, identifiableRegistry);
 | 
						|
 | 
						|
        foreach ((string key, object? value) in Public)
 | 
						|
            AssignVariable(key, type, instance, value, PUBLIC_BINDING_FLAGS, identifiableRegistry);
 | 
						|
 | 
						|
        return instance;
 | 
						|
    }
 | 
						|
 | 
						|
    private static void AssignVariable(string key, Type type, object instance, object? value, BindingFlags bindingFlags, IdentifiableRegistry identifiableRegistry)
 | 
						|
    {
 | 
						|
        if (type.GetField(key, bindingFlags) is FieldInfo fieldInfo)
 | 
						|
        {
 | 
						|
            if (typeof(IIdentifiable).IsAssignableFrom(fieldInfo.FieldType))
 | 
						|
                identifiableRegistry.QueueAssign(value?.ToString() ?? "", (entity) => fieldInfo.SetValue(instance, entity));
 | 
						|
            else
 | 
						|
                fieldInfo.SetValue(instance, value);
 | 
						|
        }
 | 
						|
        else if (type.GetProperty(key, bindingFlags) is PropertyInfo propertyInfo)
 | 
						|
        {
 | 
						|
            if (typeof(IIdentifiable).IsAssignableFrom(propertyInfo.PropertyType))
 | 
						|
                identifiableRegistry.QueueAssign(value?.ToString() ?? "", (entity) => propertyInfo.SetValue(instance, entity));
 | 
						|
            else
 | 
						|
                propertyInfo.SetValue(instance, value);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    private static void AssignVariable(string key, Type type, object instance, object? value, BindingFlags bindingFlags)
 | 
						|
    {
 | 
						|
        if (type.GetField(key, bindingFlags) is FieldInfo fieldInfo)
 | 
						|
            fieldInfo.SetValue(instance, value);
 | 
						|
        else if (type.GetProperty(key, bindingFlags) is PropertyInfo propertyInfo)
 | 
						|
            propertyInfo.SetValue(instance, value);
 | 
						|
    }
 | 
						|
}
 |