Подтвердить что ты не робот

Сериализовать статический класс?

Что произойдет, если мы сериализуем статический класс? Может ли быть создано более одного экземпляра статического класса, если мы его сериализуем?

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

    }

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

Предположим, что я XmlSerialize объект в XML файл, и в более позднее время я де-сериализации обратно к объекту. Другая копия существует в памяти (создается, когда somone мгновенно инициирует статические calss). Будет, есть две копии объекта? Если да, можем ли мы остановить это? Применяется ли он к любому классу, который следует за шаблоном singleton?

4b9b3361

Ответ 1

Нет никаких экземпляров статических классов: они абстрактны и запечатаны в IL, поэтому CLR предотвратит создание любых экземпляров. Поэтому сериализовать нечего. Статические поля никогда не сериализуются, и это единственное состояние, которое может иметь статический класс.

Ваш вопрос о сериализации XML не имеет смысла, поскольку никто не может создать экземпляр статического класса для начала.

Ответ 2

Вы не можете сериализовать классы static (или любой класс) с помощью встроенных функций сериализации .NET. Вы можете сериализовать экземпляры классов.

Ответ 3

Вы можете создать следующий класс:

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

Вы должны определить ссылку на System.Runtime.Serialization.Formatters.Soap.

Скажем, в вашей программе вы хотите сохранить следующий статический класс:

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

Вы можете использовать следующий код:

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

Если вы хотите загрузить сохраненные данные (в той же программе или в другую программу), используйте следующий код:

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

Поля A.s, A.i, A.z получат новые загруженные значения.

Ответ 4

Почему бы просто не использовать временный класс экземпляра, который является зеркалом статического класса?

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

Я знаю это немного взломанный, но он имеет ту же цель, но до сих пор разрешает Рефактору до выполнения, и проверяет ценность во время выполнения.

Ответ 5

Я нашел этот ответ очень полезным для моего класса настройки! 1000 благодаря вам!

Но я должен был внести некоторые изменения, чтобы заставить его работать из-за объекта без сериализации и изменения в BinaryFormatter из-за совместимости с ServicePack

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

Ответ 6

Другое решение, но которое читает и записывает в 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;
    }
}