2011-11-16 2 views
5

Ho il seguente pezzo di codiceCome rendere la deserializzazione XML più veloce?

public static object XmlDeserialize(string xml, Type objType) 
{ 
    StringReader stream = null; 
    XmlTextReader reader = null; 
    try 
    { 
     XmlSerializer serializer = new XmlSerializer(objType); 
     stream = new StringReader(xml); // Read xml data 
     reader = new XmlTextReader(stream); // Create reader 
     return serializer.Deserialize(reader); 
    } 
    finally 
    { 
     if(stream != null) stream.Close(); 
     if(reader != null) reader.Close(); 
    } 
} 

L'oggetto stesso è stato generato tramite xsd.exe e assomiglierà questo:

/// <remarks/> 
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")] 
[System.SerializableAttribute()] 
[System.Diagnostics.DebuggerStepThroughAttribute()] 
[System.ComponentModel.DesignerCategoryAttribute("code")] 
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true)] 
[System.Xml.Serialization.XmlRootAttribute(Namespace="", IsNullable=false)] 
public partial class MyObject { 

    private DemographicsCriteriaStateStartAge[] startAgesField; 

    private DemographicsCriteriaStateEndAge[] endAgesField; 

    private DemographicsCriteriaStateFilter[] selectedFiltersField; 

    /// <remarks/> 
    [System.Xml.Serialization.XmlArrayItemAttribute("StartAge", IsNullable=false)] 
    public DemographicsCriteriaStateStartAge[] StartAges { 
     get { 
      return this.startAgesField; 
     } 
     set { 
      this.startAgesField = value; 
     } 
    } 
    ... 

Il metodo è tipicamente chiamato così:

var obj = (MyObject) XmlDeserialize(someXmlString, typeof(MyObject)); 

La seguente riga di codice richiede sempre una parte considerevole di tempo (rispetto a tutto il resto):

XmlSerializer serializer = new XmlSerializer(objType); 

Che cosa sta succedendo qui, ad es. sta compilando un assembly di deserializzazione in background? Perché il problema delle prestazioni?

Cosa posso fare per migliorare questo problema di prestazioni?

+0

Una nota a margine, invece di 'provare ... finalmente, potresti aver usato 'using'. – svick

risposta

5

Sì, genera dinamicamente un assembly di serializzazione in fase di esecuzione. È possibile modificare questo comportamento in Visual Studio. Vai alle proprietà del progetto e alla sezione di costruzione. Esiste un'impostazione per "Genera assiemi di serializzazione" impostata su true. Questo genererà un file come YourProject.XmlSerialiser.dll durante la compilazione e interromperà questo collo di bottiglia in fase di esecuzione.

Un'eccezione, tuttavia, è che questa impostazione si applica solo ai tipi di proxy (ad esempio, proxy del servizio Web e simili). Per forzare in realtà Visual Studio 2010 per generare gli assembly di serializzazione per i tipi regolari, è necessario eseguire un pasticcio con il file di progetto (.csproj) e rimuovere/proxytypes dalla chiamata Sgen o generare un passaggio post-build per chiamare manualmente sgen.exe sull'assembly.

+0

Ho un sacco di assiemi. Devo impostare le impostazioni per l'EXE principale o per gli assembly DLL dipendenti? A proposito, ho fatto tutto questo e non ho visto alcun file YourProject.XmlSerialiser.dll in bin/debug. – AngryHacker

+0

L'ho usato solo con i proxy Web e sembra esserci qualche dibattito sul fatto che ci sia un bug qui http://connect.microsoft.com/VisualStudio/feedback/details/123088/project-does-not-generate- serializzazione-assemblaggio, anche-se-specifico-ha detto-to-do-so. Per ulteriori controlli a grana fine guardare lo strumento exe documentato qui http://msdn.microsoft.com/en-us/library/bk3w6240(v=vs.80).aspx –

+0

Penso che sarà necessario un assembly di serializzazione per assemblaggio normale . –

4

Prova la memorizzazione nella cache l'istanza del XmlSerializer per ogni tipo a livello di classe in modo da non dover ricreare ogni volta se si utilizza lo stesso tipo:

class Foo 
{ 
    private static Dictionary<Type, XmlSerializer> xmls = new Dictionary<Type, XmlSerializer>(); 

    // ... 

    public static object XmlDeserialize(string xml, Type objType) 
    { 
     StringReader stream = null; 
     XmlTextReader reader = null; 
     try 
     { 
      XmlSerializer serializer; 
      if(xmls.Contains(objType)) { 
       serializer = xmls[objType]; 
      } 
      else { 
       serializer = new XmlSerializer(objType); 
       xmls[objType] = serializer; 
      }   

      stream = new StringReader(xml); // Read xml data 
      reader = new XmlTextReader(stream); // Create reader 
      return serializer.Deserialize(reader); 
     } 
     finally 
     { 
      if(stream != null) stream.Close(); 
      if(reader != null) reader.Close(); 
     } 
    } 
} 
+0

Questa è stata la mia risposta quando ho scoperto quanto tempo ci vuole per costruire un XmlSerializer anche per una semplice classe. Ma penso che la memorizzazione nella cache avvenga comunque nella classe XmlSerializer, perché la seconda volta che si crea un XmlSerializer per un determinato tipo, non ci vuole quasi il tempo necessario. – markmuetz