zoukankan      html  css  js  c++  java
  • 【转】c# [Serializable]的作用

    http://blog.csdn.net/chinarenkai/article/details/3220452

    如果你做远程方法调用(RPC)时,比如,服务器端有个类A及对象a,客户端需要无视网络的存在,直接调用对象a。这种情况下,就需要把类A设计为可序列化的,那么它的实例a也就可以实例化了。

    说得简单点,在服务器的 命名空间中的对象a,肯定不能直接被客户端的命名空间中的一个对象调用,这不可能,对吧。
    但是如果你把服务器的对象a中的特征属性(不一定是所有属性)变成xml,传送到客户端,然后客户端用你给的特征属性可以模拟的生成一个对象a。
    这个过程就是 rpc,而要把对象a变成xml,就是序列化,反之,把xml变成模拟对象a就是反序列化。

    以上是rpc中的序列化。

    实际使用中,把app关闭的时候,内存对象可以通过序列化,可以变成可以保存的xml,这样,以便下次app再开得时候,把以前保存过的xml(或者txt等)反序列化成对象。

    一句话,序列化就是把内存中对象以一种可以保存的形式保存起来。

    需要注意的是:
    序列化可以制定序列化整个类,或者 类的某些属性。

    你是想数据持久化吗?
    首先,如果Rectangle是你自定义的类的话,必须保证这个类里面的所有状态都是可以储存的,并且要有[Serializable()]标识.
    然后你可以用 XmlSerializer类或者 BinaryFormatter类将其逐一序列化.序列化后。
    可以将其序列化成XML存进数据库也可以序列化成2进制保存.

    ==========================
    首先,你想保存某个类中的数据,那这个类最好是个实体类,
    比如

    复制代码
    [Serializable]
    [XmlRoot("Rectangle")]
    public class Rectangle{
    //fields here.
    ...
    public Rectangele(){...}
    [XmlElement("Width")]
    public int Width{get;set;}
    [XmlElement("Length")]
    public int Length{get;set;}
    }
    复制代码



    像这样的类被选择序列化才比较有意义,它要求必须有一个无参数的构造函数.
    经过类似下面的方法序列化后,将获得一个文件流

    复制代码
    Rectangle rec = new Rectangle{Width = 5,Length = 6};
    using (FileStream fs = new FileStream(fileFullName, FileMode.Create, FileAccess.Write, FileShare.Read))
    {
    XmlSerializer xs = new XmlSerializer(rec.GetType());
    //序列化成Xml文件.
    xs.Serialize(fs, rec);
    //使用文件流
    ...
    }
    复制代码


    同样可以序列化成 2进制文件流.:

    using (FileStream fs = new FileStream(fileFullName, FileMode.Open, FileAccess.ReadWrite))
    {
    BinaryFormatter bf = new BinaryFormatter();
    bf.Serialize(fs, rec);
    }


    另外,如果你的类用来记录状态,比如是否跟远程主机连接成功,之类的,那么序列化是没有意义的.因为当你反序列化的时候,他的环境已经变了,而以前保存的状态已经不稳定了.

    序列化,是记录类中所有可序列化的信息.并可以还原.
    另外一个选择呢,就是只记录内容,用内容重新实例化类:
    比如

    Rectangle rec = new Rectangle{Width = 5,Length = 6};



    rec 你只需要在数据库中记录Width = 5,Length = 6
    在将来,你可以根据 Width,Length的值重新实例化Rectangle类.
    至于集合,可类推.

    选择性序列化
     类通常包含不应被序列化的字段。例如,假设某个类用一个成员变量来存储线程 ID。当此类被反序列化时,序列化此类时所存储的 ID 对应的线程可能不再运行,所以对这个值进行序列化没有意义。可以通过使用 NonSerialized 属性标记成员变量来防止它们被序列化,如下所示:
     

    复制代码
     [Serializable]
     public class MyObject
     {
     public int n1;
     [NonSerialized] public int n2;
     public String str;
     }
    复制代码


     自定义序列化
     可以通过在对象上实现 ISerializable 接口来自定义序列化过程。这一功能在反序列化后成员变量的值失效时尤其有用,但是需要为变量提供值以重建对象的完整状态。要实现 ISerializable,需要实现 GetObjectData方法以及一个特殊的构造函数,在反序列化对象时要用到此构造函数。以下代码示例说明了如何在前一部分中提到的 MyObject 类上实现 ISerializable。
     

    复制代码
     [Serializable]
     public class MyObject : ISerializable
     {
     public int n1;
     public int n2;
     public String str;
     
     public MyObject()
     {
     }
     
     protected MyObject(SerializationInfo info, StreamingContext context)
     {
     n1 = info.GetInt32("i");
     n2 = info.GetInt32("j");
     str = info.GetString("k");
     }
     
     public virtual void GetObjectData(SerializationInfo info,
     StreamingContext context)
     {
     info.AddValue("i", n1);
     info.AddValue("j", n2);
     info.AddValue("k", str);
     }
     }
    复制代码


     在序列化过程中调用 GetObjectData 时,需要填充方法调用中提供的 SerializationInfo 对象。只需按名称/值对的形式添加将要序列化的变量。其名称可以是任何文本。只要已序列化的数据足以在反序列化过程中还原对象,便可以自由选择添加至 SerializationInfo 的成员变量。如果基对象实现了 ISerializable,则派生类应调用其基对象的 GetObjectData 方法。
     
     需要强调的是,将 ISerializable 添加至某个类时,需要同时实现 GetObjectData 以及特殊的构造函数。如果缺少 GetObjectData,编译器将发出警告。但是,由于无法强制实现构造函数,所以,缺少构造函数时不会发出警告。如果在没有构造函数的情况下尝试反序列化某个类,将会出现异常。在消除潜在安全性和版本控制问题等方面,当前设计优于 SetObjectData 方法。例如,如果将 SetObjectData 方法定义为某个接口的一部分,则此方法必须是公共方法,这使得用户不得不编写代码来防止多次调用 SetObjectData 方法。可以想象,如果某个对象正在执行某些操作,而某个恶意应用程序却调用此对象的 SetObjectData 方法,将会引起一些潜在的麻烦。

  • 相关阅读:
    怎么安装Python?
    Ramnit蠕虫病毒分析和查杀
    Exphub[漏洞利用脚本库]
    SMBv3远程代码执行漏洞复现(CVE-2020-0796)
    Tomcat AJP 文件包含漏洞复现(CVE-2020-1938)
    Fastjson远程代码执行漏洞复现
    信息收集之——旁站、C段
    Redis未授权访问漏洞复现与利用
    CSS
    MVC控制器路由
  • 原文地址:https://www.cnblogs.com/sggggr/p/11818588.html
Copyright © 2011-2022 走看看