C# 序列化静态类?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1293496/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 14:47:01  来源:igfitidea点击:

Serialize a Static Class?

c#serializationsingleton

提问by Bhaskar

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 MyClass
{
    public static MyClass()
    {

    }

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

Suppose I XmlSerialize the object to a XML file, and at a later time I de-serialize back to a object. Another copy exists in the memory (created when somone instintiated the static calss for the first time). Will, there be two copy of the of the object? If yes, can we stop that? Does it apply to any class which follows the singleton pattern?

假设我 XmlSerialize 对象到一个 XML 文件,稍后我反序列化回一个对象。内存中存在另一个副本(当有人第一次使用静态类时创建)。请问,有两个对象的副本吗?如果是,我们能阻止吗?它适用于任何遵循单例模式的类吗?

采纳答案by Jon Skeet

There are never anyinstances 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.

从来没有静态类的任何实例:它们在 IL 中都是抽象的和密封的,因此 CLR 将阻止创建任何实例。因此没有什么可序列化的。静态字段永远不会被序列化,这是静态类可以拥有的唯一一种状态。

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

您关于 XML 序列化的问题毫无意义,因为没有人可以从创建静态类的实例开始。

回答by Mehrdad Afshari

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

您不能static使用内置的 .NET 序列化功能序列化类(或任何类)。您只能序列化类的实例

回答by Mikhail Semenov

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.

您必须定义对 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.

字段 As、Ai、Az 将获得新的加载值。

回答by SilverX

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.

我知道这有点像 hack,但它实现了相同的目的,同时仍然允许在运行前进行重构,并在运行时进行值验证。

回答by andi

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

我发现这个答案对我的设置课程非常有用!1000谢谢你!

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

但是我不得不做一些改变才能使它工作,因为一个不可序列化的对象和由于服务包兼容性而更改为 BinaryFormatter

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

回答by headkaze

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.

另一种解决方案,但一种在 xml 中读写的解决方案。您还可以使用字段上方的 [NonSerialized] 属性来防止它被序列化。

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