39 votes

Sérialiser une classe statique?

Qu'advient-il si nous sérialiser une classe statique? Pouvez plus d'une instance de la classe statique est créé si nous sérialiser?

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

    }

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

Supposons que je XmlSerialize l'objet d'un fichier XML, et à un moment plus tard, je dé-sérialiser retour à un objet. Une autre copie existe dans la mémoire (créé lors de la somone instintiated la statique calss pour la première fois). Allons, il y a deux copie de l'objet? Si oui, pouvons-nous nous arrêter? Ne s'applique à toute la classe qui suit le pattern singleton?

55voto

Jon Skeet Points 692016

Il n'y a jamais d' instances de classes statiques: elles sont à la fois abstraites et scellées dans l'IL, de sorte que le CLR empêche la création d'instances. Par conséquent, il n'y a rien à sérialiser. Les champs statiques ne sont jamais sérialisés, et c'est le seul type d'état qu'une classe statique peut avoir.

Votre question sur la sérialisation XML n’a aucun sens, personne n’ayant jamais pu créer une instance de la classe statique.

17voto

Mehrdad Afshari Points 204872

Vous ne pouvez pas sérialiser les classes static (ni aucune classe) à l'aide des fonctionnalités de sérialisation .NET intégrées. Vous ne pouvez sérialiser que des instances de classes.

14voto

Mikhail Semenov Points 309

Vous pouvez créer la classe suivante:

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;
            }
        }
    }
}

Vous devez définir une référence à System.Moment de l'exécution.La sérialisation.Des formateurs.Le savon.

Dites, dans votre programme, vous voulez économiser de l'électricité statique de la classe:

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

Vous pouvez utiliser le code suivant:

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

Si vous souhaitez charger les données enregistrées (dans le même programme ou dans un autre programme), utilisez le code suivant:

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

Les champs A. s, A. i, A. z obtiendrez le nouveau, chargé de valeurs.

8voto

SilverX Points 759

Pourquoi ne pas simplement utiliser une classe d'instance temporaire qui est un miroir de la classe statique?

 [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;
    }
}
 

Je sais que c'est un peu un bidouillage, mais il poursuit le même objectif, tout en permettant toujours à Refactor de s'exécuter avant l'exécution et de valider la valeur pendant l'exécution.

0voto

andi Points 1

J'ai trouvé cette réponse vraiment utile pour ma classe de réglages! 1000 grâce à vous!

Mais j'ai dû faire quelques changements pour le faire fonctionner, en raison d'un objet non sérialisable et passer à BinaryFormatter en raison de la compatibilité du service pack.

 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;
        }
    }
}
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X