Подтвердить что ты не робот

Сохранять объект, который не помечен как сериализуемый

Мне нужно сохранить объект, который не помечен атрибутом serializable. Объект - из сторонней библиотеки, которую я не могу изменить.

Мне нужно сохранить его в постоянном месте, например, в файловой системе, поэтому оптимальным решением будет сериализация объекта в файл, но поскольку он не помечен как сериализуемый, это не прямой решение.

Это довольно сложный объект, который также содержит коллекцию других объектов.

Есть ли у вас какие-либо данные о том, как это решить? Код никогда не будет работать в рабочей среде, поэтому я уверен в почти любом решении и производительности.

4b9b3361

Ответ 1

XmlSerializer может быть полезным, прежде всего, попробовать, если типы общедоступны и т.д.

Если это не удается, v2 protobuf-net (в этом случае вам нужно будет строить из исходного кода, но я могу помочь) работает с объектами без атрибута, поэтому идеально подходит для типов вне вашего контроля - вам просто нужно сказать, что (через DSL). Код v2 не является полным, но он охватывает наиболее распространенные сценарии, включая коллекции и т.д. (Неполная работа - это, в основном, обратные вызовы и перечисления).

Ответ 2

Вы можете написать рекурсивный метод, который будет работать на графике объекта с использованием отражения, чтобы сохранить объект... Отведение его назад может быть намного сложнее. Кто знает, содержат ли какие-либо из этих объектов ссылки на неуправляемые или системные ресурсы. Если бы я сделал что-нибудь из этого ореха, я бы пошел на метод .GetFields(...) на тип.

Другая идея...

Если вы делаете это только для ускорения разработки, почему бы не обернуть свои кланы своими собственными классами адаптеров. Это позволит вам заменить библиотеки сторонних разработчиков вашими упрощенными макетными классами и дать им больше шансов для замены и повторного использования позже.

Больной, как есть... Это было легче, чем я думал. (Хотя это работает... пожалуйста, рассмотрите возможность обертывания сторонних классов.)

public static class Tools
{
    public static XElement AsXml(this object input)
    {
        return input.AsXml(string.Empty);
    }
    public static XElement AsXml(this object input, string name)
    {
        if (string.IsNullOrEmpty(name))
            name = input.GetType().Name;

        var xname = XmlConvert.EncodeName(name);

        if (input == null)
            return new XElement(xname);

        if (input is string || input is int || input is float /* others */)
            return new XElement(xname, input);

        var type = input.GetType();
        var fields = type.GetFields(BindingFlags.Instance |
                                    BindingFlags.NonPublic)
                         .Union(type.GetFields(BindingFlags.Instance |
                                               BindingFlags.Public));

        var elems = fields.Select(f => f.GetValue(input)
                                        .AsXml(f.Name));

        return new XElement(xname, elems);
    }
    public static void ToObject(this XElement input, object result)
    {
        if (input == null || result == null)
            throw new ArgumentNullException();

        var type = result.GetType();
        var fields = type.GetFields(BindingFlags.Instance |
                                    BindingFlags.NonPublic)
                         .Union(type.GetFields(BindingFlags.Instance |
                                               BindingFlags.Public));

        var values = from elm in input.Elements()
                     let name = XmlConvert.DecodeName(elm.Name.LocalName)
                     join field in fields on name equals field.Name
                     let backType = field.FieldType
                     let val = elm.Value
                     let parsed = backType.AsValue(val, elm)
                     select new
                     {
                         field,
                         parsed
                     };

        foreach (var item in values)
            item.field.SetValue(result, item.parsed);            
    }

    public static object AsValue(this Type backType,
                                      string val,
                                      XElement elm)
    {
        if (backType == typeof(string))
            return (object)val;
        if (backType == typeof(int))
            return (object)int.Parse(val);
        if (backType == typeof(float))
            return (float)int.Parse(val);

        object ret = FormatterServices.GetUninitializedObject(backType);
        elm.ToObject(ret);
        return ret;
    }
}
public class Program
{
    public static void Main(string[] args)
    {
        var obj = new { Matt = "hi", Other = new { ID = 1 } };
        var other = new { Matt = "zzz", Other = new { ID = 5 } };
        var ret = obj.AsXml();
        ret.ToObject(other);
        Console.WriteLine(obj); //{ Matt = hi, Other = { ID = 1 } }
        Console.WriteLine(other); //{ Matt = hi, Other = { ID = 1 } }
    }
}

Ответ 4

Я не знаю, является ли это излишним для вашего использования, но я в последнее время играл с db4o. Он будет сохраняться на любом объекте, просто вызовите объект IObjectContainer.Store(объект), и он будет легким и основанным на файлах. Не требует установки.

У меня еще не было проблем с этим.

Ответ 5

///Here OBJECT is Class name and Object_to_write is instance  
XmlSerializer serializer = new XmlSerializer(typeof(OBJECT)); 
using (TextWriter writer = new StreamWriter(@"C:\Xml.xml"))
{
    serializer.Serialize(writer, OBJECT_to_Write); 
}