При работе в Unity нам может понадобиться использовать классы-капсулы для сериализации некоторых нативных классов. Зачастую среди кандидатов на такие вот классы у нас используются классы, в которых есть откуда подтянуть эти данные. Среди таких - классы для работы с рефлексией.
namespace Serialization { public abstract class SerializeContainer<T> where T: class { private T _value; public T value { get { if (isNull) return null; if (_value == null && !isNull) _value = Getter(); isNull = _value == null; return _value; } set { _value = value; isNull = (value == null); if (!isNull) Setter(value); } } public bool isNull = true; protected abstract T Getter(); protected abstract void Setter(T value); } }
using System; namespace Serialization { [Serializable] public class SerializeType : SerializeContainer<Type> { public SerializeType() { value = null; } public SerializeType(Type value) { this.value = value; } public string fullName; protected override Type Getter() { return Type.GetType(fullName); } protected override void Setter(Type value) { fullName = value.AssemblyQualifiedName ?? ""; } } }
using System; using System.Reflection; namespace Serialization { [Serializable] public class SerializeFieldInfo : SerializeContainer<FieldInfo> { public SerializeFieldInfo() { value = null; } public SerializeFieldInfo(FieldInfo value) { this.value = value; } public SerializeFieldInfo(Type type, string fieldname) { this.s_parentType = new SerializeType(type); this.fieldname = fieldname; } public SerializeType s_parentType; public string fieldname; protected override FieldInfo Getter() { return s_parentType.value.GetField(fieldname); } protected override void Setter(FieldInfo value) { s_parentType = new SerializeType(value.DeclaringType); fieldname = value.Name; } } }
using System; using System.Linq; using System.Reflection; namespace Serialization { [Serializable] public class SerializeMethod : SerializeContainer<MethodInfo> { public SerializeMethod() { value = null; } public SerializeMethod(MethodInfo value) { this.value = value; } public string[] parametersInfo; public SerializeType s_parentType = new SerializeType(); public string methodName; public int parameterCount { get { return parametersInfo.Length; } } protected override MethodInfo Getter() { return s_parentType.value .GetMethods(BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance) .Where(x => x.Name == methodName) .Where(x => { var ps = x.GetParameters(); return ps.Length == parametersInfo.Length && !ps.Where((t, i) => GetParameterInfo(t) != parametersInfo[i]).Any(); }).FirstOrDefault(); } protected override void Setter(MethodInfo value) { s_parentType = new SerializeType(value.DeclaringType); parametersInfo = value.GetParameters().Select(x => GetParameterInfo(x)).ToArray(); methodName = value.Name; } private static string GetParameterInfo(ParameterInfo parameterInfo) { return parameterInfo.ToString(); } } }
using System; using System.Linq; namespace Serialization { [Serializable] public class SerializeEnum : SerializeContainer<Enum> { public SerializeType type; public int index; protected override Enum Getter() { return Enum.Parse(type.value, Enum.GetNames(type.value)[index]) as Enum; } protected override void Setter(Enum value) { type = new SerializeType(value.GetType()); index = Enum.GetValues(value.GetType()).Cast<Enum>().ToList().FindIndex(x => x.Equals(value)); } } }
MethodInfo оказался объемным, но зато так он поддерживает дженерик параметры.
Указанные сериализаторы позволяют хранить типы. Например:
myTypeStorage = new SerializeType(typeof(int)); var myType = myTypeStorage.value;
Плюсом является то, что при этом капсула адекватно сохраняется в сцене (в то время как сам по себе тип сохранить нельзя).
Так как вычисления методов происходят "ленивым кешированием" расчеты будут произведены только при первом обращении к полю value.
Где применять?
Да хоть где. Лично мне понадобилось для написания редактора сценариев, ибо там методы/типы/поля дело очень важное.
Смотрите также:
Комментарии
Здесь еще никто не оставил комментарий
CollectableItemData.cs
[CreateMenuItem(fileName = "newItem", menuName = "Data/Items/Collectable", order = 51]