C#对象序列化

C# 对象序列化三种方式

一、常规序列化方式

对象标记为可序列化,然后把不需要序列化的字段加上[NonSerialized]特性

序列化测试对象SerializeTest

	[Serializable]
    public class SerializeTest
    {
        
        [NonSerialized]
        private string _name;

        public SerializeTest(string name, string ip, int port, ITestInfo testInfo)
        {
            Name = name;
            IP = ip;
            Port = port;
            TestInfo = testInfo;
        }

        public string Name { get { return _name; } set { _name = value; } }

        public string IP { get; set; }

        public int Port { get; set; }

        public ITestInfo TestInfo { get; set; }
    }

序列化对象包含的对象接口

    public interface ITestInfo
    {
        string Message { get; set; }

        int Id { get; set; }

        List<string> InfoList { get; set; }
    }

序列化对象包含的对象接口实现

    [Serializable]
	public class TestInfo : ITestInfo
    {
        public TestInfo(string message, int id, List<string> infoList)
        {
            Message = message;
            Id = id;
            InfoList = infoList;
        }

        public string Message { get; set; }
        public int Id { get; set; }
        public List<string> InfoList { get; set; }

    }

然后通过窗体的保存按钮进行对象序列化,加载时反序列化,进行测试,代码如下:

   public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            var serializeTest = SerializeUtils.DeserializeBinaryFromFile("F:\\temp\\test.dat");
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            ITestInfo testInfo = new TestInfo("消息",1,new List<string> { "测试","121"});
            SerializeTest serializeTest = new SerializeTest("序列化测试","127.0.0.1",8080,testInfo);
            SerializeUtils.SerializeBinaryToFile(serializeTest, "F:\\temp\\test.dat");
        }
       
    }

序列化工具类

 public class SerializeUtils
    {
        public static object DeserializeBinaryFromFile(string file)
        {
            FileStream fs = null;
            try
            {
                fs = new FileStream(file, FileMode.Open, FileAccess.ReadWrite);

                BinaryFormatter deserializer = new BinaryFormatter();
                object newobj = deserializer.Deserialize(fs);

                fs.Close();
                return newobj;
            }
            catch (Exception ex)
            {
                if (fs != null) fs.Close();
                return null;
            }
        }

        public static bool SerializeBinaryToFile(object request, string file)
        {
            try
            {
                BinaryFormatter serializer = new BinaryFormatter();
                FileStream fs = new FileStream(file, FileMode.Create, FileAccess.ReadWrite);
                serializer.FilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Low;
                serializer.Serialize(fs, request);
                fs.Close();
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }
    }

测试结果如下:

点击保存待保存对象截图:
在这里插入图片描述

重新启动反序列化结果如下:
在这里插入图片描述

Name为null,没有保存

二、实现ISerializable接口

通过实现ISerializable接口的GetObjectData方法,把需要序列化保存的数据通过info.AddValue方法进行添加,此时不需要使用特性 [NonSerialized]
添加有参构造来实现对象的数据的获取

将SerializeTest类改造如下

[Serializable]
public class SerializeTest : ISerializable
{
    public SerializeTest(string name, string ip, int port, ITestInfo testInfo)
    {
        Name = name;
        IP = ip;
        Port = port;
        TestInfo = testInfo;
    }

    public string Name { get; set; }

    public string IP { get; set; }

    public int Port { get; set; }

    public ITestInfo TestInfo { get; set; }

    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue("IP", this.IP);
        info.AddValue("Port", this.Port);
        info.AddValue("TestInfo", this.TestInfo);
    }

    protected SerializeTest(SerializationInfo info, StreamingContext context)
    {
        try
        {
            SerializationInfoEnumerator enumerator = info.GetEnumerator();
            this.IP = GetValueBySerializationInfo<string>(info, "IP");
            this.Port = GetValueBySerializationInfo<int>(info, "Port");
            while (enumerator.MoveNext())
            {
                if (enumerator.Name == "TestInfo") this.TestInfo = (ITestInfo)enumerator.Value;
            }
        }
        catch (Exception e)
        {
        }
    }

    /// <summary>
    /// 根据key从序列化对象获取值
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="info"></param>
    /// <param name="key"></param>
    /// <returns></returns>
    public T GetValueBySerializationInfo<T>(SerializationInfo info, string key)
    {
        try
        {
            return (T)info.GetValue(key, typeof(T));
        }
        catch
        {
            return default(T);
        }
    }
}

删除test.dat文件重新测试,测试结果一致。

三、通过反射方式

在方式二的基础上通过反射自动将需要序列化的数据进行保存和获取,注意此方式将不需要序列化的属性使用特性[XmlIgnore]标记,对于需要序列化的属性较多时效果较好,SerializeTest类改造如下:

[Serializable]
public class SerializeTest : ISerializable
{
    public SerializeTest(string name, string ip, int port, ITestInfo testInfo)
    {
        Name = name;
        IP = ip;
        Port = port;
        TestInfo = testInfo;
        TestInfo = testInfo;
    }
    [XmlIgnore]
    public string Name { get; set; }

    public string IP { get; set; }

    public int Port { get; set; }
    public ITestInfo TestInfo { get; set; }


    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        var properties = GetProperties();
        foreach (var property in properties)
        {
            if (IsNeedSerializedProperty(property))
            {
                info.AddValue(property.Name, GetPropertyValue(property));
            }
        }
    }

    protected SerializeTest(SerializationInfo info, StreamingContext context)
    {
        try
        {
            var properties = GetProperties();
            foreach (var property in properties)
            {
                if (IsNeedSerializedProperty(property))
                {
                    try
                    {
                        SetPropertyValue(property, GetValueBySerializationInfo<object>(info, property.Name));
                    }
                    catch (Exception ex)
                    {

                    }
                }
            }
        }
        catch (Exception e)
        {
        }
    }
    private PropertyInfo[] GetProperties()
    {
        return this.GetType().GetProperties();
    }
    /// <summary>
    /// 属性是否可序列化
    /// </summary>
    /// <param name="propertyInfo"></param>
    /// <returns></returns>
    private bool IsNeedSerializedProperty(PropertyInfo propertyInfo)
    {
        if (propertyInfo == null) return false;
        return propertyInfo.GetCustomAttribute(typeof(XmlIgnoreAttribute)) == null
                && propertyInfo.CanWrite;
    }
    private object GetPropertyValue(PropertyInfo propertyInfo)
    {
        if (propertyInfo == null) return null;
        return this.GetType().GetProperty(propertyInfo.Name).GetValue(this, null);
    }
    private void SetPropertyValue(PropertyInfo propertyInfo, object value)
    {
        if (propertyInfo == null) return;
        this.GetType().GetProperty(propertyInfo.Name).SetValue(this, value);
    }
    /// <summary>
    /// 根据key从序列化对象获取值
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="info"></param>
    /// <param name="key"></param>
    /// <returns></returns>
    public T GetValueBySerializationInfo<T>(SerializationInfo info, string key)
    {
        try
        {
            return (T)info.GetValue(key, typeof(T));
        }
        catch
        {
            return default(T);
        }
    }
}

删除test.dat文件重新测试,测试结果一致。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

坏菠萝

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值