2011-01-31 16 views
27

Sto tentando di utilizzare uno System.Dynamic.ExpandoObject così posso creare dinamicamente le proprietà in fase di runtime. Successivamente, ho bisogno di passare un'istanza di questo oggetto e il meccanismo utilizzato richiede la serializzazione.Posso serializzare un ExpandoObject in .NET 4?

Naturalmente, quando si tenta di serializzare il mio oggetto dinamico, ottengo l'eccezione:

System.Runtime.Serialization.SerializationException was unhandled.

Type 'System.Dynamic.ExpandoObject' in Assembly 'System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' is not marked as serializable.

Posso serializzare l'ExpandoObject? C'è un altro approccio alla creazione di un oggetto dinamico che è serializzabile? Forse usando un wrapper DynamicObject?

ho creato un semplice Windows Form esempio per duplicare l'errore:

using System; 
using System.Windows.Forms; 
using System.IO; 
using System.Runtime.Serialization; 
using System.Runtime.Serialization.Formatters.Binary; 
using System.Dynamic; 

namespace DynamicTest 
{ 
    public partial class Form1 : Form 
    { 
     public Form1() 
     { 
      InitializeComponent(); 
     } 

     private void button1_Click(object sender, EventArgs e) 
     {    
      dynamic dynamicContext = new ExpandoObject(); 
      dynamicContext.Greeting = "Hello"; 

      IFormatter formatter = new BinaryFormatter(); 
      Stream stream = new FileStream("MyFile.bin", FileMode.Create, 
              FileAccess.Write, FileShare.None); 
      formatter.Serialize(stream, dynamicContext); 
      stream.Close(); 
     } 
    } 
} 
+1

Breve di attuare un manuale routine di serializzazione, sono propenso a dire che se non è contrassegnato come 'Serializable' quindi, no, abbastanza semplicemente. –

risposta

20

Non riesco a serializzare ExpandoObject, ma posso serializzare manualmente DynamicObject. Quindi, usando i metodi TryGetMember/TrySetMember di DynamicObject e implementando ISerializable, posso risolvere il mio problema che consisteva nel serializzare realmente un oggetto dinamico.

Ho implementato il seguente nella mia semplice applicazione di test:

using System; 
using System.Windows.Forms; 
using System.IO; 
using System.Runtime.Serialization; 
using System.Runtime.Serialization.Formatters.Binary; 
using System.Collections.Generic; 
using System.Dynamic; 
using System.Security.Permissions; 

namespace DynamicTest 
{ 
    public partial class Form1 : Form 
    { 
     public Form1() 
     { 
      InitializeComponent(); 
     } 

     private void button1_Click(object sender, EventArgs e) 
     {    
      dynamic dynamicContext = new DynamicContext(); 
      dynamicContext.Greeting = "Hello"; 
      this.Text = dynamicContext.Greeting; 

      IFormatter formatter = new BinaryFormatter(); 
      Stream stream = new FileStream("MyFile.bin", FileMode.Create, FileAccess.Write, FileShare.None); 
      formatter.Serialize(stream, dynamicContext); 
      stream.Close(); 
     } 
    } 

    [Serializable] 
    public class DynamicContext : DynamicObject, ISerializable 
    { 
     private Dictionary<string, object> dynamicContext = new Dictionary<string, object>(); 

     public override bool TryGetMember(GetMemberBinder binder, out object result) 
     { 
      return (dynamicContext.TryGetValue(binder.Name, out result)); 
     } 

     public override bool TrySetMember(SetMemberBinder binder, object value) 
     { 
      dynamicContext.Add(binder.Name, value); 
      return true; 
     } 

     [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)] 
     public virtual void GetObjectData(SerializationInfo info, StreamingContext context) 
     { 
      foreach (KeyValuePair<string, object> kvp in dynamicContext) 
      { 
       info.AddValue(kvp.Key, kvp.Value); 
      } 
     } 

     public DynamicContext() 
     { 
     } 

     protected DynamicContext(SerializationInfo info, StreamingContext context) 
     { 
      // TODO: validate inputs before deserializing. See http://msdn.microsoft.com/en-us/library/ty01x675(VS.80).aspx 
      foreach (SerializationEntry entry in info) 
      { 
       dynamicContext.Add(entry.Name, entry.Value); 
      } 
     } 

    } 
} 

e Why does SerializationInfo not have TryGetValue methods? avevano il pezzo di puzzle mancante per mantenere le cose semplici.

+3

Aveva qualche dubbio nel rispondere alla mia domanda, ma sembra essere incoraggiato: http://meta.stackexchange.com/questions/9933/is-there-a-convention-for-accepting-my-own-answer-to -my-own-question –

9

ExpandoObject implementa IDictionary<string, object>, ad esempio:

class Test 
{ 
    static void Main() 
    { 
     dynamic e = new ExpandoObject(); 
     e.Name = "Hello"; 

     IDictionary<string, object> dict = (IDictionary<string, object>)e; 

     foreach (var key in dict.Keys) 
     { 
      Console.WriteLine(key); 
     } 

     dict.Add("Test", "Something"); 

     Console.WriteLine(e.Test); 

     Console.ReadKey(); 
    } 
} 

si potrebbe scrivere il contenuto del dizionario in un file , quindi creare un nuovo ExpandoObject tramite la deserializzazione, ricondurlo a un dizionario e scrivere nuovamente le proprietà?

+0

Se l'output deve essere in XML, 'IDictionary <,>' non può essere serializzato con [XmlSerializer] (http://msdn.microsoft.com/EN-US/library/swxzdhc0.aspx) ma può essere serializzato con [DataContractSerializer] (http://msdn.microsoft.com/EN-US/library/ms405768.aspx) sebbene l'output sia troppo dettagliato. Personalmente penso che JsonFx menzionato in altre risposte faccia meglio il serializzazione di 'ExpandoObject'. – Mike

8

Forse un po 'tardi per rispondere, ma io uso jsonFx per serializzare e deserializzare expandoObjects e funziona molto bene:

serializzazione:

dim XMLwriter As New JsonFx.Xml.XmlWriter 
dim serializedExpando as string =XMLwriter.Write(obj) 

deserializzazione

dim XMLreader As New JsonFx.Xml.XmlReader 
Dim obj As ExpandoObject = XMLreader.Read(Str) 
+3

Bello. Il JsonWriter mi ha appena salvato un sacco di tempo! Ecco il Git per JsonFx se qualcuno ne ha bisogno: https://github.com/jsonfx/jsonfx –

+1

ho provato questo. Funziona perfettamente per la serializzazione dell'oggetto dinamico, ma la deserializzazione mostra un'eccezione: Nome proprietà oggetto previsto o fine dell'oggetto (Inizio oggetto). – sharmakeshav

+0

Usa JsonReader e Writer invece di Xml per correggere l'eccezione precedente :) – faztp12

Problemi correlati