2009-08-18 20 views
36

Was passiert, wenn wir eine statische Klasse serialisieren? Kann mehr als eine Instanz der statischen Klasse erstellt werden, wenn wir sie serialisieren?Serialisieren einer statischen Klasse?

[Serializable] 
public static class MyClass 
{ 
    public static MyClass() 
    { 

    } 

    public static bool IsTrue() 
    { 
     return true; 
    } 
} 

Angenommen XMLSERIALIZE ich das Objekt in eine XML-Datei, und zu einem späteren Zeitpunkt ich de-Serialisierung auf ein Objekt zurück. Eine weitere Kopie existiert im Speicher (erstellt, wenn somone zum ersten Mal den statischen Wert eingegeben hat). Wird es zwei Kopien des Objekts geben? Wenn ja, können wir das stoppen? Gilt es für jede Klasse, die dem Singleton-Muster folgt?

+0

Ich denke, es gibt hier einige Verwirrung zwischen "singleton" und "statisch" ... –

+1

"Angenommen, ich XmlSerialize das Objekt": Welches Objekt? es gibt dort kein Objekt (d. h. keine Instanz), da die Klasse statisch ist –

Antwort

52

Es gibt keine beliebige Instanzen von statischen Klassen: Sie sind beide abstrakt und versiegelt in der IL, so dass die CLR verhindert, dass alle Instanzen erstellt werden. Daher gibt es nichts zu serialisieren. Statische Felder werden niemals serialisiert, und das ist die einzige Art von Status, die eine statische Klasse haben kann.

Ihre Frage zur XML-Serialisierung macht keinen Sinn, da niemand jemals eine Instanz der statischen Klasse erstellt haben kann.

+1

was ist das: 'öffentliche statische Klasse Konstanten { öffentliche const Zeichenfolge Con1 =" con1 "; public const Zeichenfolge Con2 = "con2"; } ' Ich möchte dies dynamisch an Javascript übergeben, in diesem Fall macht eine Art der Serialisierung Sinn. Ja, das Wort _serialize_ kann heute leicht unterschiedliche Bedeutungen haben. –

+0

@orhor: Was meinst du mit "pass das"? Wenn Sie "eine Sammlung von Konstanten" übergeben möchten, können Sie das relativ einfach tun, aber ich denke nicht, dass dies die normale Bedeutung des Begriffs "serialisieren" ändert. –

+0

ok, Literally: Ich muss einen Service von Javascript aufrufen und seine Antwort in JavaScript-Objekt in Bezug auf Service C# Typ deserialisieren. Mit den etwas anderen Bedeutungen meinte ich diese zwei Alternativen: 1. ein _object_ übersetzen (das eine Instanz impliziert) in ein speicherbares Format 2. alles übersetzen - nur Speicherdaten, ein Typ oder was auch immer Sie wollen in ein Textformat. Zum Beispiel übertragbar über ein Web von Service zu Client aber nichts für ungut, bitte, ich bin nicht beleidigend Ihre Antwort, ich bin nur (hoffentlich) erweitern das Spektrum der Informationen auf dieser Seite. Und danke für Fragen. –

17

Sie können keine static Klassen (oder eine andere Klasse) mit den integrierten .NET-Serialisierungsfunktionen serialisieren. Sie können nur Instanzen von Klassen serialisieren.

+0

Aber, kann das obige Szenario existieren? Das heißt, kann es mehr als eine Instanz einer statischen Klasse geben? – Bhaskar

+1

Nein. Es kann nicht passieren. –

12

Sie können die folgende Klasse erstellen:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Runtime.Serialization.Formatters.Soap; 
using System.Reflection; 
using System.IO; 

namespace SerializeStatic_NET 
{ 
    public class SerializeStatic 
    { 
     public static bool Save(Type static_class, string filename) 
     { 
      try 
      { 
       FieldInfo[] fields = static_class.GetFields(BindingFlags.Static | BindingFlags.Public); 
       object[,] a = new object[fields.Length,2]; 
       int i = 0; 
       foreach (FieldInfo field in fields) 
       { 
        a[i, 0] = field.Name; 
        a[i, 1] = field.GetValue(null); 
        i++; 
       }; 
       Stream f = File.Open(filename, FileMode.Create); 
       SoapFormatter formatter = new SoapFormatter();     
       formatter.Serialize(f, a); 
       f.Close(); 
       return true; 
      } 
      catch 
      { 
       return false; 
      } 
     } 

     public static bool Load(Type static_class, string filename) 
     { 
      try 
      { 
       FieldInfo[] fields = static_class.GetFields(BindingFlags.Static | BindingFlags.Public);     
       object[,] a; 
       Stream f = File.Open(filename, FileMode.Open); 
       SoapFormatter formatter = new SoapFormatter(); 
       a = formatter.Deserialize(f) as object[,]; 
       f.Close(); 
       if (a.GetLength(0) != fields.Length) return false; 
       int i = 0; 
       foreach (FieldInfo field in fields) 
       { 
        if (field.Name == (a[i, 0] as string)) 
        { 
         field.SetValue(null, a[i,1]); 
        } 
        i++; 
       };     
       return true; 
      } 
      catch 
      { 
       return false; 
      } 
     } 
    } 
} 

Sie müssen einen Verweis auf System.Runtime.Serialization.Formatters.Soap definieren.

Say, in Ihrem Programm möchten Sie die folgende statische Klasse speichern:

public static class A 
{ 
    public static string s; 
    public static int i; 
    public static double z; 
} 

Sie können den folgenden Code verwenden:

bool ok = SerializeStatic.Save(typeof(A), "c:\\tests\\a.dat"); 

Wenn Sie die gespeicherten Daten geladen werden soll (in der das gleiche Programm oder in einem anderen Programm), verwenden Sie den folgenden Code:

bool ok2 = SerializeStatic.Load(typeof(A), "c:\\tests\\a.dat"); 

Die Felder As, Ai, Az wird ge t die neuen, geladenen Werte.

7

Warum nicht einfach eine temporäre Instanzklasse verwenden, die ein Spiegel der statischen Klasse ist?

[XmlRoot] 
public class SerializeClass 
{ 
    public int Number { 
     get; 
     set; 
    } 
} 

public static class SerializedClass { 

    public static int Number { 
     get; 
     set; 
    } 


    public static void Serialize(Stream stream) { 

     SerializeClass obj = new SerializeClass(); 
     obj.Number = Number; 

     XmlSerializer serializer = new XmlSerializer(typeof(SerializeClass)); 
     serializer.Serialize(stream, obj); 
    } 

    public static void Deserialize(Stream stream) { 

     XmlSerializer serializer = new XmlSerializer(typeof(SerializeClass)); 
     SerializeClass obj = (SerializeClass)serializer.Deserialize(stream); 

     Number = obj.Number; 
    } 
} 

Ich weiß, es ist ein bisschen wie ein Hack, aber es Übertragungskameras den gleichen Zweck, während noch Umgestalten vor der Laufzeit ermöglicht, und den Wert Validierung während der Laufzeit.

+1

Keine Erklärung für die Down-Abstimmung? Statische Klassen können nicht serialisiert werden. Dies ist ein akzeptabler Workaround. Ich frage mich, warum Reflektion in diesem Szenario die beste Antwort ist. Es benötigt mehr Ressourcen und ist viel langsamer als einfach die Daten in ein Objekt zu kopieren, das serialisiert werden kann. hmmm – SilverX

+0

Der Reflektionsweg ist VIEL weniger Codezeilen, wenn Sie viele Klassen oder Klassen mit vielen Feldern haben. – LeeCambl

0

Ich fand diese Antwort wirklich nützlich für meine Einstellungsklasse! 1000 dank dir!

Aber ich hatte einige Änderungen zu tun, um es wegen Arbeit zu machen, einen nicht serialisierbaren Objekt und Änderung BinaryFormatter aufgrund Servicepack Kompatiblität

public class SerializeStatic 
{ 
    public static bool Save(Type static_class, string filename) 
    { 
     try 
     { 
      FieldInfo[] fields = static_class.GetFields(BindingFlags.Static | BindingFlags.Public); 

      object[,] a = new object[fields.Length-1,2]; //one field can´t be serialized, so shouldn´t be counted 
      int i = 0; 
      foreach (FieldInfo field in fields) 
      { 
       if(field.Name == "db") continue; // db cant be serialized! so get away.. not very pretty but does its job :) 
       a[i, 0] = field.Name; 
       a[i, 1] = field.GetValue(null); 
       i++; 
      }; 
      Stream f = File.Open(filename, FileMode.Create); 
      BinaryFormatter formatter = new BinaryFormatter(); //Soapformatter -> .NET 4.5 -> doesn´t run under xp! 
      // SoapFormatter formatter = new SoapFormatter(); 
      formatter.Serialize(f, a); 
      f.Close(); 
      return true; 
     } 
     catch(Exception ex) 
     { 
      System.Windows.Forms.MessageBox.Show(ex.ToString()); //Better error messages 
      return false; 
     } 
    } 

    public static bool Load(Type static_class, string filename) 
    { 
     try 
     { 
      FieldInfo[] fields = static_class.GetFields(BindingFlags.Static | BindingFlags.Public); 
      object[,] a; 
      Stream f = File.Open(filename, FileMode.Open); 
      BinaryFormatter formatter = new BinaryFormatter(); 
      a = formatter.Deserialize(f) as object[,]; 
      f.Close(); 
      if (a.GetLength(0) != fields.Length-1) return false; 

      foreach (FieldInfo field in fields) 
       for(int i=0;i< fields.Length-1;i++) //I ran into problems that some fields are dropped,now everyone is compared to everyone, problem fixed 
        if (field.Name == (a[i, 0] as string)) 
         field.SetValue(null, a[i,1]); 
      return true; 
     } 
     catch(Exception ex) 
     { 
      System.Windows.Forms.MessageBox.Show(ex.ToString()); 
      return false; 
     } 
    } 
} 
0

Eine andere Lösung, aber eine, die und schreibt in xml liest. Sie können auch das Attribut [NonSerialized] über einem Feld verwenden, um zu verhindern, dass es serialisiert wird.

public static class SerializeStatic 
{ 
    public static bool Serialize(Type staticClass, string fileName) 
    { 
     XmlTextWriter xmlWriter = null; 

     try 
     { 
      xmlWriter = new XmlTextWriter(fileName, null); 

      xmlWriter.Formatting = Formatting.Indented; 

      xmlWriter.WriteStartDocument(); 

      Serialize(staticClass, xmlWriter); 

      xmlWriter.WriteEndDocument(); 

      return true; 
     } 
     catch (Exception ex) 
     { 
      System.Windows.Forms.MessageBox.Show(ex.ToString()); 

      return false; 
     } 
     finally 
     { 
      if (xmlWriter != null) 
      { 
       xmlWriter.Flush(); 
       xmlWriter.Close(); 
      } 
     } 
    } 

    public static void Serialize(string name, object obj, XmlTextWriter xmlWriter) 
    { 
     Type type = obj.GetType(); 
     XmlAttributeOverrides xmlAttributeOverrides = new XmlAttributeOverrides(); 
     XmlAttributes xmlAttributes = new XmlAttributes(); 
     xmlAttributes.XmlRoot = new XmlRootAttribute(name); 
     xmlAttributeOverrides.Add(type, xmlAttributes); 
     XmlSerializer xmlSerializer = new XmlSerializer(type, xmlAttributeOverrides); 

     xmlSerializer.Serialize(xmlWriter, obj); 
    } 

    public static bool Serialize(Type staticClass, XmlTextWriter xmlWriter) 
    { 
     FieldInfo[] fieldArray = staticClass.GetFields(BindingFlags.Static | BindingFlags.Public); 

     xmlWriter.WriteStartElement(staticClass.Name); 

     foreach (FieldInfo fieldInfo in fieldArray) 
     { 
      if (fieldInfo.IsNotSerialized) 
       continue; 

      string fieldName = fieldInfo.Name; 
      string fieldValue = null; 
      Type fieldType = fieldInfo.FieldType; 
      object fieldObject = fieldInfo.GetValue(fieldType); 

      if (fieldObject != null) 
      { 
       if (fieldType.GetInterface("IDictionary") != null || fieldType.GetInterface("IList") != null) 
       { 
        Serialize(fieldName, fieldObject, xmlWriter); 
       } 
       else 
       { 
        TypeConverter typeConverter = TypeDescriptor.GetConverter(fieldInfo.FieldType); 
        fieldValue = typeConverter.ConvertToString(fieldObject); 

        xmlWriter.WriteStartElement(fieldName); 
        xmlWriter.WriteString(fieldValue); 
        xmlWriter.WriteEndElement(); 
       } 
      } 
     } 

     xmlWriter.WriteEndElement(); 

     return true; 
    } 

    public static bool Deserialize(Type staticClass, string fileName) 
    { 
     XmlReader xmlReader = null; 

     try 
     { 
      xmlReader = new XmlTextReader(fileName); 

      Deserialize(staticClass, xmlReader); 

      return true; 
     } 
     catch (Exception ex) 
     { 
      System.Windows.Forms.MessageBox.Show(ex.ToString()); 

      return false; 
     } 
     finally 
     { 
      if (xmlReader != null) 
      { 
       xmlReader.Close(); 
       xmlReader = null; 
      } 
     } 
    } 

    public static object Deserialize(string name, Type type, XmlReader xmlReader) 
    { 
     XmlAttributeOverrides xmlAttributeOverrides = new XmlAttributeOverrides(); 
     XmlAttributes xmlAttributes = new XmlAttributes(); 
     xmlAttributes.XmlRoot = new XmlRootAttribute(name); 
     xmlAttributeOverrides.Add(type, xmlAttributes); 
     XmlSerializer xmlSerializer = new XmlSerializer(type, xmlAttributeOverrides); 

     return xmlSerializer.Deserialize(xmlReader); 
    } 

    public static bool Deserialize(Type staticClass, XmlReader xmlReader) 
    { 
     FieldInfo[] fieldArray = staticClass.GetFields(BindingFlags.Static | BindingFlags.Public); 
     string currentElement = null; 

     while (xmlReader.Read()) 
     { 
      if (xmlReader.NodeType == XmlNodeType.EndElement) 
       continue; 

      if (xmlReader.NodeType == XmlNodeType.Element) 
      { 
       currentElement = xmlReader.Name; 
      } 

      foreach (FieldInfo fieldInfo in fieldArray) 
      { 
       string fieldName = fieldInfo.Name; 
       Type fieldType = fieldInfo.FieldType; 
       object fieldObject = fieldInfo.GetValue(fieldType); 

       if (fieldInfo.IsNotSerialized) 
        continue; 

       if (fieldInfo.Name == currentElement) 
       { 
        if (typeof(IDictionary).IsAssignableFrom(fieldType) || typeof(IList).IsAssignableFrom(fieldType)) 
        { 
         fieldObject = Deserialize(fieldName, fieldType, xmlReader); 

         fieldInfo.SetValueDirect(__makeref(fieldObject), fieldObject); 
        } 
        else if (xmlReader.NodeType == XmlNodeType.Text) 
        { 
         TypeConverter typeConverter = TypeDescriptor.GetConverter(fieldType); 
         object value = typeConverter.ConvertFromString(xmlReader.Value); 

         fieldInfo.SetValue(fieldObject, value); 
        } 
       } 
      } 
     } 

     return true; 
    } 
} 
Verwandte Themen