158 lines
5.8 KiB
C#

using System;
using System.Collections.Generic;
using System.Reflection;
using Syntriax.Engine.Core.Factory;
namespace Syntriax.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 isFullySerializable = 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 (!isFullySerializable && !privatePropertyInfo.HasAttribute<SerializeAttribute>())
continue;
object? value = privatePropertyInfo.GetValue(@class);
if (value is IEntity entity)
Private.Add(privatePropertyInfo.Name, entity.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 (!isFullySerializable && !publicPropertyInfo.HasAttribute<SerializeAttribute>())
continue;
object? value = publicPropertyInfo.GetValue(@class);
if (value is IEntity entity)
Public.Add(publicPropertyInfo.Name, entity.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 (!isFullySerializable && !privateFieldInfo.HasAttribute<SerializeAttribute>())
continue;
object? value = privateFieldInfo.GetValue(@class);
if (value is IEntity entity)
Private.Add(privateFieldInfo.Name, entity.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 (!isFullySerializable && !publicFieldInfo.HasAttribute<SerializeAttribute>())
continue;
object? value = publicFieldInfo.GetValue(@class);
if (value is IEntity entity)
Public.Add(publicFieldInfo.Name, entity.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(EntityRegistry? entityRegistry)
{
if (entityRegistry 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, entityRegistry);
foreach ((string key, object? value) in Public)
AssignVariable(key, type, instance, value, PUBLIC_BINDING_FLAGS, entityRegistry);
return instance;
}
private static void AssignVariable(string key, Type type, object instance, object? value, BindingFlags bindingFlags, EntityRegistry entityRegistry)
{
if (type.GetField(key, bindingFlags) is FieldInfo fieldInfo)
{
if (typeof(IEntity).IsAssignableFrom(fieldInfo.FieldType))
entityRegistry.QueueAssign(value?.ToString() ?? "", (entity) => fieldInfo.SetValue(instance, entity));
else
fieldInfo.SetValue(instance, value);
}
else if (type.GetProperty(key, bindingFlags) is PropertyInfo propertyInfo)
{
if (typeof(IEntity).IsAssignableFrom(propertyInfo.PropertyType))
entityRegistry.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);
}
}