Сериализаторы для рефлексии

Published
При работе в 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);
    }
}
» Type
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 ?? "";
        }
    }
}
» FIeldInfo
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;
        }
    }
}
» MethodInfo
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();
        }
    }
}
» Enum - не совсем в тему рефлексии, но тоже сериализатор
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.
Где применять?
Да хоть где. Лично мне понадобилось для написания редактора сценариев, ибо там методы/типы/поля дело очень важное.


Views: 1 022

Комментарии пока отсутcтвуют.