Serialize a Static Class?

后端 未结 6 1143
耶瑟儿~
耶瑟儿~ 2020-11-27 06:25

What happens if we serialize a static class? Can more than one instance of the static class be created if we serialize it?

[Serializable]
public static class         


        
相关标签:
6条回答
  • 2020-11-27 06:55

    I found this answer realy useful for my setting class! 1000 thanks to you!

    But i had to do some changes to make it working, due to a non-serializable object and change to BinaryFormatter due to servicepack compatiblity

    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 讨论(0)
  • 2020-11-27 06:59

    Why not just use a temporary instance class that is a mirror of the static class?

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

    I know it's a bit of a hack, but it acheives the same purpose, while still allowing Refactor before runtime, and value validation during runtime.

    0 讨论(0)
  • 2020-11-27 07:06

    You can't serialize static classes (or any class whatsoever) using built-in .NET serialization features. You can only serialize instances of classes.

    0 讨论(0)
  • 2020-11-27 07:06

    You may create the following class:

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

    You must define a reference to System.Runtime.Serialization.Formatters.Soap.

    Say, in your program you want to save the following static class:

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

    You may use the following code:

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

    If you want to load the saved data (in the same program or in another program), use the following code:

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

    The fields A.s, A.i, A.z will get the new, loaded values.

    0 讨论(0)
  • 2020-11-27 07:08

    There are never any instances of static classes: they are both abstract and sealed in the IL, so the CLR will prevent any instances being created. Therefore there is nothing to serialize. Static fields are never serialized, and that's the only sort of state that a static class can have.

    Your question about XML serialization makes no sense, as no-one can ever have created an instance of the static class to start with.

    0 讨论(0)
  • 2020-11-27 07:15

    Another solution but one that reads and writes in xml. You can also use the [NonSerialized] attribute above a field to prevent it from being serialized.

    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;
        }
    }
    
    0 讨论(0)
提交回复
热议问题