2010-04-07 3 views
21

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

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

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

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

+12

Известные последние слова ... 'Код никогда не будет работать в производственной environment': Op –

+0

@Matthew: Да, right :-) +1 – driis

+0

Хех, я знаю :) Это только ускорить некоторое время разминки во время dev, так что это не имеет никакого смысла нигде. – lasseeskildsen

ответ

9

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

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

+0

protobuf-net выглядит довольно красиво. Требуется ли это беззазорные конструкторы? – lasseeskildsen

+0

@lasseeskildsen - на данный момент это так, да, но, поскольку у меня есть это, я уверен, что могу добавить подход WCF (не называть никакого ctor). Это займет всего несколько минут (это просто вызов 'FormatterServices.GetUninitializedObject'). –

+0

Если у вас есть пример стороннего API, я мог бы подтянуть пример v2. –

2

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

У меня пока не возникли проблемы с этим.

3

Это один из способов вы можете сделать это:

http://www.codeproject.com/KB/dotnet/Surrogate_Serialization.aspx

здесь ссылка MSDN показывая его:

http://msdn.microsoft.com/en-us/magazine/cc188950.aspx

+0

Ссылки больше не работают. Первая статья: [link] (https: //web.archive.org/web/20101213020136/http: //www.codeproject.com/kb/dotnet/Surrogate_Serialization.aspx) Вторая статья: [link] (https://web.archive.org/web/20141231105711/http://msdn .microsoft.com/en-us/magazine/cc188950.aspx) – milosa

5

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

Еще одна идея ...

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

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

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 } } 
    } 
} 
+0

+1 Обертка - великолепная идея в подобном сценарии. – Filburt

+0

Да, я просто попытался создать быстрое решение для сохранения и восстановления объектов на основе частных значений. Сохранение довольно легко; проблема заключается в их восстановлении. Если у вас нет доступа к конструктору с меньшим параметром, это может быть невозможно. –

+0

Я не несу ответственности, если приведенный выше код заставляет мир взорваться, и вся жизнь во Вселенной приходит к резкому завершению –

0
///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); 
} 
+0

> Объект от сторонней библиотеки, которую я не могу изменить. XmlSerializer может вызывать InvalidOprationException: [объект] не может быть сериализован, потому что у него нет конструктора без параметров. –

Смежные вопросы