clr via c# 运行时序列化
1,快速了解序列化----windows IO 系统,FileStream,BinaryFormatter,SoapFormatter--不支持泛型.
public class SerializeRef
{
public static void CallQuick()
{
dynamic objectgrap = new List<string>() { "jeff", "kristin", "aldan", "grant" }.ToArray<string>(); using (var st = new FileStream("mxb.xml", FileMode.Create))
{
SoapFormatter formatter = new SoapFormatter();
formatter.Serialize(st, objectgrap);
st.Position = 0;
objectgrap = null;
var objectgrap1 = ((string[])formatter.Deserialize(st)).ToList<string>();
objectgrap1.ForEach(x => Display(0, x));
} }
private static void Display(int indent, string Format, params object[] obj)
{
Console.Write(new string(' ', indent * 2));
Console.WriteLine(Format, obj);
}
}
利用BinaryFormatter.Serialize配合流进行对象图的写入.
利用BinaryFormatter.DeSerialize进行对象图的还原
流对象st.Postion如果没设置会报错.
2, 利用序列化创建对象的深拷贝.
private static object DeepClone(object ori)
{
using(MemoryStream ms=new MemoryStream())
{
BinaryFormatter bf = new BinaryFormatter();
bf.Context = new StreamingContext(StreamingContextStates.Clone);
bf.Serialize(ms, ori);
ms.Position = 0;
return bf.Deserialize(ms);
}
}
//注意Context中的一个用法,表明这是一个流的一个克隆过程,告诉其他线程该如何处理原对象.
3,利用序列化保存和恢复程序的状态.
public static void CallSerilalMultiple()
{
List<Customer> s_customers = new List<Customer>() { new Customer("abc"),};
List<order> s_orders = new List<order>() { new order("abc"), };
using(var fs=new FileStream("mxb.dat", FileMode.OpenOrCreate))
{
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(fs, s_customers);
bf.Serialize(fs,s_orders);
s_customers = null;
s_orders = null;
GC.Collect();
}
using (var fs = new FileStream("mxb.dat", FileMode.OpenOrCreate))
{
BinaryFormatter bf = new BinaryFormatter();
s_customers = (List<Customer>)(bf.Deserialize(fs));
s_orders = (List<order>)(bf.Deserialize(fs));
}
s_customers.ForEach(x => Display(0, x.name));
s_orders.ForEach(x => Display(0, x.name));
}//resultCustomerabc ;成功的反序列化原来的对象. orderabc;成功反序列化原来的对象.
4,让对象可序列化 定制特性SerializableAttribute
只能用于 class,struct,枚举类型和委托类型(后两者总是可序列化).
Serializable特性不被派生类继承,
5,控制序列化
序列化应用于类型时,所有的实列字段都会被序列化.(类的对象),使用NonSerialized,这样,某个字段就不会被序列化.当反序列化的时候,该字段自动清0.
类可设定四个方法进行控制:
- private void OnSerializing(StreamContext context)---序列化之前[OnSerializing]
- private void OnSerialized(streamContext context)---序列化完成后[OnSerialized]
- private void OnDeSerialized(streamContext context)---反序列化之前[OnDeSerializing]
- private void OnDeSerialized(stream Context context)---反序列化之后[OnDeSerialized]
序列化一组对象前,先调用标记OnSerializing特性的所有方法.接着序列化所有字段,接着调用标记OnSerialized特性的所有方法.
反序列化前,先调用OnDeserializing特性的所有方法,然后反序列化所有的对象字段,然后调用标记了OnDeserialized方法. 运行OnDeserialized方法前,会进行由内而外的反序执行(先执行对象指向对象的方法,最后才是对象的方法). 6,格式化器序列化类型实列的过程 1,使用FormatterServices.GetSerializableMembers,获取(public,private)的可序列化字段 一个MemberInfo[] 数组 2,调用FormatterServices.GetObjectData(obj,memberinfos)来获取各个字段的data,一个object[]数组,和上面对应. public static void CallHowSerialize()
{
Customer ct = new Customer("nameadef");
//1,通过该函数获得类的public和private的字段.
MemberInfo[] mis= FormatterServices.GetSerializableMembers(typeof(Customer));//可以获取隐藏的属性字段.可获取私有字段.
Array.ForEach<MemberInfo>(mis, x => Display(0,"{0}", x.Name));
//获取字段的值...
Display(0, "");
object[] objs = FormatterServices.GetObjectData(ct, mis);
Array.ForEach<object>(objs, x => Display(0, "{0}", x.ToString()));
}
3,将程序集标识和类型完整名称写入流中
4,遍历两个数组的元素,将名称和值写入流中
7,反序列化实列的流程
1,格式化器从流中读取程序集标识和完整的类名称,如果程序集未加载,就试图加载程序集.如果已经加载,就调用函数
FormatterServices.GetTypeFromAssembly(assembly,string name)获得需要反序列化的对象的类型.
2,格式化器调用FormatterServices的静态方法
public static object GetUninitializedObject(Type type)为对象分配内存,但是不为对象调用构造器.然而,所有的字节都
被初始化为null,或0;
3,格式化器现在构造,并初始化一个MemberInfo数组,获得MemberInfo[]数组,表示需要反序列化的字段
4,格式化器根据流中包含的字段值反序列化为一个object[]数组.
5,将新分配的对象,MemberInfo数组以及Object数组的引用传递给FormatterServices的静态方法
public static object PopulateObjectMembers(
object obj,
MemberInfo[] mis,
object[] datas);
举列:----
public static void CallHowSerialize()
{
Customer ct = new Customer("nameadef");
//1,通过该函数获得类的public和private的字段.
MemberInfo[] mis= FormatterServices.GetSerializableMembers(typeof(Customer));//可以获取隐藏的属性字段.可获取私有字段.
//无法获取隐藏的属性字段.
Display(0, "Filds to be Serialized:");
Array.ForEach<MemberInfo>(mis, x => Display(1,"{0}", x.Name));
//获取字段的值...
Display(0, "Filds Data to be Serialized:");
object[] objs = FormatterServices.GetObjectData(ct, mis);
Array.ForEach<object>(objs, x => Display(1, "{0}", x.ToString()));
//反序列化对象
Customer dct = null;
//获得需要反序列化对象的类型:
Type t = FormatterServices.GetTypeFromAssembly(Assembly.GetEntryAssembly(), typeof(Customer).FullName);
//创建一个初始化但未调用构造器的类对象
dct = (Customer)FormatterServices.GetUninitializedObject(t);
Display(0, "\n Before Deserialized FieldsData");
Display(1,"name is {0}",dct.name??"None");
dct =(Customer) FormatterServices.PopulateObjectMembers(dct, mis, objs);
Display(0, "\n After Deserialized FieldsData");
Display(0, "name is {0}", dct.name);
}Filds to be Serialized: name t <Props>k__BackingField
Filds Data to be Serialized: Customernameadef 0 0
Before Deserialized FieldsData name is None
After Deserialized FieldsData
name is Customernameadef
1,反序列化过程不调用构造器
2,通过上面函数可以设定私有字段.
8,控制序列化和反序列化的数据----ISerializable接口:
void GetObjectData(SerializationInfo info,StreamingContext context)----一旦某个类实现了它,其派生类也必须实现.(所以,实现了该接口的类最好是密封的sealed).
如果有该接口,那么在序列化的时候,开始使用info.add添加(key,可序列化对象).然后序列化SerializationInfo对象,并序列化其中引用的所有序列化对象.
在反序列化的时候,就反序列化SerializationInfo对象,然后调用反序列化构造器,将这个参数和StreamingContext对象传递给反序列化构造器.
当使用GetValue对象获得的对象和你视图获取的对象不符合,则将调用对象的IFormatterConverter对象,将 GetValue取得的对象进行转换
s2 = (SerializeTwo)info.GetValue("s2", typeof(object));//后一个是获得对象要转换的类型.
1,首先创建一个类 SerializeOne
首先该类有3个字段.
该类有两个构造器
该类有一个反序列化构造器
该类的序列化函数将字段加入info
该类的反序列化构造器将信息读出并显示
internal class SerializedOne:ISerializable,IDeserializationCallback
{
private string m_name;
private int m_int;
private List<string> list=new List<string>(); public SerializedOne():this("initial",default(int),null)
{ }
public SerializedOne(string name,int int1,params string[] strs)
{
m_name = name;
m_int = int1;
if(strs!=null)list.AddRange(strs); } public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("List", list);
info.AddValue("m_name", m_name);
info.AddValue("m_int", m_int); } public void OnDeserialization(object sender)
{
Console.WriteLine("DeSerialized!");
}
protected SerializedOne(SerializationInfo info,StreamingContext context)//反序列化构造器,进行反序列化一个新的未构造对象后,进行运行;
{
list =(List<string>) info.GetValue("List",typeof(object));
m_int = (int)info.GetValue("m_int", typeof(int));
m_name = (string)info.GetValue("m_name", typeof(string)); Console.WriteLine("DeSerialized Constructor");
foreach(var enter in info)
{
Console.WriteLine(enter.Name+" : "+enter.Value);
}
}
public override string ToString()
{
string str=string.Format("\nm_name={0}:m_int={1}", m_name, m_int);
int index = 0;
list.ForEach(x => str = str + string.Format("\nItem {0} = {1} ", index++, x));
return str;
}
public virtual void Display() { Console.WriteLine(this.ToString()); }
}
2,创建一个类2继承自类1..(类2同时继承了类1的所有字段)
该类重写了类1的几个方法
internal class SerializeTwo:SerializedOne,ISerializable
{
public string name;
public SerializeTwo(string name):base(name,100,"abc","efg") { this.name = name; }
private SerializeTwo(SerializationInfo info, StreamingContext context):base(info,context)//反序列化构造器,进行反序列化一个新的未构造对象后,进行运行;
{
name = (string)info.GetValue("name", typeof(string));
} public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
info.AddValue("name", this.name); }
public override string ToString()
{
return base.ToString() + string.Format("\nSerializedTwo's name ={0}", this.name);
}
public override void Display()
{ Console.WriteLine(ToString());
}
}
3,进行测试:
public static void CallISerializedTwo()
{
Console.WriteLine("Show Fileds of SerializeTwo [[[[[:--------------");
MemberInfo[] mis = FormatterServices.GetSerializableMembers(typeof(SerializeTwo));//可以获取隐藏的属性字段.可获取私有字段.
Array.ForEach<MemberInfo>(mis, x => Display(1, "{0}", x.Name)); Console.WriteLine("Show Fileds of SerializeTwo ]]]]:--------------");
SerializeTwo so = new SerializeTwo("mxb");
so.Display();
using (var fs = new FileStream("mxb.dat", FileMode.OpenOrCreate))
{
SerializedGJ.Serialize(fs, new BinaryFormatter(), so);
}
so = null; using (var fs = new FileStream("mxb.dat", FileMode.OpenOrCreate))
{
so = (SerializeTwo)SerializedGJ.DeSerialize(fs, new BinaryFormatter());
so.Display();
}
}Show Fileds of SerializeTwo [[[[[:-------------- name SerializedOne+m_name SerializedOne+m_int SerializedOne+list
Show Fileds of SerializeTwo ]]]]:--------------
m_name=mxb:m_int=100
Item 0 = abc
Item 1 = efg
SerializedTwo's name =mxb
DeSerialized Constructor
List : System.Collections.Generic.List`1[System.String]
m_name : mxb
m_int : 100
name : mxb
DeSerialized!
m_name=mxb:m_int=100
Item 0 = abc
Item 1 = efg
SerializedTwo's name =mxb
结果: 1,表明派生类继承了基类的字段
2,当未序列化的时候,各个字段的值
3,将so引用清0,然后进行反序列化
4,显示了info类的Key,value内容,
5,显示类2的所有字段的值.
9,利用如何序列化一个没有被标记为序列化的类
[Serializable]
internal sealed class NoSerializableToSerialized:ISerializable //我写的一个可以包装未设置序列化类的类.
{
private object m_obj;
private const BindingFlags c_bf = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField; public object Obj { get { return m_obj; } }
public NoSerializableToSerialized(object obj) { m_obj = obj; } private NoSerializableToSerialized(SerializationInfo info, StreamingContext context)
{
Type t = (Type)info.GetValue("TypeOfObject", typeof(Type));//反序列化m_obj的对象类型.
m_obj = Activator.CreateInstance(t);//创建类型实列.
FieldInfo[] mis = null; if (m_obj.GetType().IsDefined(typeof(SerializableAttribute)))//如果是序列化类调用....
{
mis = (FieldInfo[])FormatterServices.GetSerializableMembers(m_obj.GetType()); }
else//非序列化类调用....
{
mis = m_obj.GetType().GetTypeInfo().GetFields(c_bf); } for (int i = 0; i < mis.Length; i++)
{
var mi = mis[i]; if (!mi.FieldType.GetTypeInfo().IsDefined(typeof(SerializableAttribute)))//非序列化类,迭代解析.
{ var objss = (NoSerializableToSerialized)info.GetValue(mi.Name + i, typeof(NoSerializableToSerialized));
mi.SetValue(m_obj, objss.Obj);
}
else//否则直接获得对象.
{
mi.SetValue(m_obj, info.GetValue(mi.Name + i, mi.FieldType));
} } }
//自定义序列化函数
public void GetObjectData(SerializationInfo info, StreamingContext context)
{ info.AddValue("TypeOfObject", m_obj.GetType(), typeof(Type));//将对象类型序列化
FieldInfo[] mis = null;
object[] objs = null;
if (m_obj.GetType().IsDefined(typeof(SerializableAttribute)))//如果是序列化类型,调用GetSerializableMembers
{
mis =(FieldInfo[])FormatterServices.GetSerializableMembers(m_obj.GetType());
objs = FormatterServices.GetObjectData(m_obj, mis);
Console.WriteLine("\n defined serial");
}
else//如果是非序列化,调用GetFields.
{
mis = m_obj.GetType().GetTypeInfo().GetFields(c_bf);
objs = FormatterServices.GetObjectData(m_obj, mis);
} for (int i = 0; i < mis.Length; i++)
{
var mi = mis[i];
var obj = objs[i];
//如果Field是非序列化对象,则进行包装,再序列化.否则直接加入Info
if (!mi.FieldType.GetTypeInfo().IsDefined(typeof(SerializableAttribute)))
{
info.AddValue(mi.Name + i, new NoSerializableToSerialized(obj));
}
else
{
info.AddValue(mi.Name + i, obj);
} } } }
10,单实列对象序列化
public sealed class Singleton : ISerializable
{
private static readonly Singleton s_theOneObject = new Singleton();
public string Name = "Jeff";
public DateTime Date=DateTime.Now;
private Singleton() { } public static Singleton GetSingleton() { return s_theOneObject; } void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
{
info.SetType(typeof(SingletionSerializationHelper));
}
private Singleton(SerializationInfo info, StreamingContext context)//该函数未运行.
{
Console.WriteLine("Deserialization Singletion");
}
[Serializable]
private sealed class SingletionSerializationHelper : IObjectReference
{
public object GetRealObject(StreamingContext context)
{
return Singleton.GetSingleton();
}
}
}
1,使用SetType表示在序列化的时候将序列化一个SingletionSerializationHelper对象,----将该对象的程序集和类型信息写入序列化中
2,在反序列化的时候,格式化器知道这是一个由类型转换来的对象.所以它首先反序列化成一个SingletionSerializationHelper对象.
注意:该对象必须实现接口IObjectReference,然后调用该对象的GetRealObject对象---让它返回一个所需要的对象.(这个方法主要用于对单实列类进行保存.
11,序列化代理:(利用代理可以重写和覆盖,将类型反馈为一个不同的版本)
序列化代理必须事件ISerializationSurrogate接口
该接口实现了2个函数:
GetObjectData(Object, SerializationInfo, StreamingContext)
//用序列化对象所需的数据填充所提供的 SerializationInfo。
SetObjectData(Object, SerializationInfo, StreamingContext, ISurrogateSelector)
反序列化时,利用其将SerializationInfo中
- 当某个类型 和 序列化代理关联的时候,那么,序列化这个对象,就调用了GetObjectData方法,(ISerializable)中的方法.并且
第一个参数为,该类型的实列,第二个参数为格式化器提供的Info.
当反序列化的时候,首先使用FormatterServices.GetUninitializedObject()建立一个关联类型的未初始化的实列.该实列的所有的Field是NUll,或者0;
然后这个参数作为第一个参数传给SetObjectData,这个参数可用,可不用.
- 首先创建一个需要代理的类(测试用,非实现Serializable)
public class TestForSurrogate//一个测试类,当序列化的时候,不管序列化时间,反序列化的时候,更新其时间
{
public DateTime dt = DateTime.Now;
public String Name;
public TestForSurrogate(string name)
{
Name = name;
}
}
- 然后创建一个代理类,一个实现了ISerializationSurrogate接口的类
public sealed class MySurrogateForSurrogateTest : ISerializationSurrogate
{
public void GetObjectData(object obj, SerializationInfo info, StreamingContext context)
{
TestForSurrogate Myboj = (TestForSurrogate)obj;
Myboj.dt = DateTime.Now;
Console.WriteLine(Myboj.Name+Myboj.dt.ToString());
info.AddValue("Name", Myboj.Name);
info.AddValue("time", Myboj.dt);
} public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)
{
TestForSurrogate Myboj = (TestForSurrogate)obj;
Myboj.dt = (DateTime)info.GetValue("time",typeof(object));
Myboj.Name = (string)info.GetValue("Name", typeof(object));
Console.WriteLine(Myboj.Name + Myboj.dt.ToString());
return Myboj;
}
}
然后创建一个surrogateSelector对象,并且进行绑定
SurrogateSelector selector = new SurrogateSelector();
selector.AddSurrogate(typeof(TestForSurrogate), formatter.Context, new MySurrogateForSurrogateTest());
然后将其赋值给,Formmater的SurrogateSelecotor属性
formatter.SurrogateSelector = selector;
- 然后就能工作了,当序列化 一个TestForSurrogate对象,就会调用MySurrogateForSurrogateTest.GetObjectData
- 当反序列化时候,就会调用MySurrogateForSurrogateTest.SetObjectData
注意,Selector实现了接口ISurrogateSelector接口:
ChainSelector 将Selector链接起来
GetNextSelector 获得下一个Selector
GetSurrgate,在Selector链中查找.
相当于KeyValue<type,Surrogate)----组成了一个 Selector,
Selector.Chain(Selector1)将Selector1加入到Selector链中.
12,反序列化的时候重写程序集/类型-----------SerializationBinder对象的使用.
1,自己实现一个SerializationBinder的派生类.
public class MySerializationBinder : SerializationBinder
{
public override Type BindToType(string assemblyName, string typeName)
{
Console.WriteLine("BInderToType...");
Console.WriteLine("\n" + assemblyName);
Console.WriteLine("\n" + typeName);
//return Type.GetType(typeName +","+ assemblyName);//加,号,因为否则生成的typename是不完整的.
return typeof(TestForSurrogate1);
} }
2,其赋值给Formmater.Binder
formatter.Binder = new MySerializationBinder();
3,实现绑定类型类,将---类TestForSurrogate返回给类TestForSurrogate1
public sealed class TestForSurrogate1:ISerializable//一个测试类,当序列化的时候,不管序列化时间,反序列化的时候,更新其时间
{
public DateTime dt = DateTime.Now;
public String Name;
public TestForSurrogate1(string name)
{
Name = name;
}
private TestForSurrogate1(SerializationInfo info, StreamingContext context)
{
Console.WriteLine("test1 Deserialized..");
try
{
info.GetValue("Test1", typeof(TestForSurrogate1));
}
catch(Exception)
{
Console.WriteLine("it's From Surrogate v1.0");
this.Name = (string)info.GetValue("Name", typeof(object));
this.dt = DateTime.Now;
} } public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("Test1", this);
}
}
4,测试如下代码
public static void Call1()
{
using (var st = new FileStream("mxb.xml", FileMode.Create))
{
SoapFormatter formatter = new SoapFormatter();
SurrogateSelector selector = new SurrogateSelector();
selector.AddSurrogate(typeof(TestForSurrogate), formatter.Context, new MySurrogateForSurrogateTest());
formatter.SurrogateSelector = selector;
formatter.Binder = new MySerializationBinder();
formatter.Serialize(st, new TestForSurrogate("mxb"));
//必须,表明要格式化的位置?
st.Position = 0;
var objectgrap1 = formatter.Deserialize(st);
Console.WriteLine(objectgrap1.GetType().ToString());
Console.WriteLine(((TestForSurrogate1)objectgrap1).Name); }
}
}
其结果如下:
mxb2020/2/19 21:32:55
BInderToType... ClrFromCSharp_2_2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=11fccde6e91ad1e9 ClrFromCSharp_2_2.LearnSerialize.TestForSurrogate
test1 Deserialized..
it's From Surrogate v1.0
ClrFromCSharp_2_2.LearnSerialize.TestForSurrogate1
mxb
xml文件内容如下
<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:clr="http://schemas.microsoft.com/soap/encoding/clr/1.0" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<a1:Singleton_x002B_SingletionSerializationHelper id="ref-1" xmlns:a1="http://schemas.microsoft.com/clr/nsassem/ClrFromCSharp_2_2.LearnSerialize/ClrFromCSharp_2_2%2C%20Version%3D1.0.0.0%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3D11fccde6e91ad1e9">
<Name id="ref-3">Jeff</Name>
</a1:Singleton_x002B_SingletionSerializationHelper>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
表明对象序列化的绑定器和绑定的类别. ------------就是创建了一个单实列的SingletionSerializationHelper.
当反序列化的时候,格式化器通过selector知道这个Selector绑定的类别
然后创建该类别非初始化实列
然后传递给SetObjectData的第一个参数.执行这个函数.
--------------
当由Binder之后,对象在反序列化的时候,首先
- 执行Binder的BinderToType函数,然后返回了一个Type.
- 然后,如果该类型有ISerialize接口,调用反序列化构造器.
- 否则,调用默认反序列化过程,见上面.
上面的列子很有意思
由于Selector和Surrogate的缘故,首先当序列化一个TestForSurrogate对象的时候,会先调用代理的序列化函数.
但是,由于binder的作用,再返回的时候,因为,创建了一个TestForSurrogate1对象,会调用TestForSurrogate1,的反序列化构造器.
clr via c# 运行时序列化的更多相关文章
- 重温CLR(十八) 运行时序列化
序列化是将对象或对象图转换成字节流的过程,反序列化是将字节流转换回对象图的过程.在对象和字节流之间转换是很有用的机制. 1 应用程序的状态(对象图)可轻松保存到磁盘文件或数据库中,并在应用程序下次运行 ...
- 《CLR Via C#》读书笔记:24.运行时序列化
一.什么是运行时序列化 序列化的作用就是将对象图(特定时间点的对象连接图)转换为字节流,这样这些对象图就可以在文件系统/网络进行传输. 二.序列化/反序列化快速入门 一般来说我们通过 FCL 提供的 ...
- 深入探索.NET框架内部了解CLR如何创建运行时对象
原文地址:http://msdn.microsoft.com/en-us/magazine/cc163791.aspx 原文发布日期: 9/19/2005 原文已经被 Microsoft 删除了,收集 ...
- 深入探索.NET内部了解CLR如何创建运行时对象
前言 SystemDomain, SharedDomain, and DefaultDomain. 对象布局和内存细节. 方法表布局. 方法分派(Method dispatching). 因为公共语言 ...
- 【C#进阶系列】24 运行时序列化
序列化是将对象或者对象图(一堆有包含关系的对象)转换成字节流的过程.而反序列化就是将字节流转为对象或对象图. 主要用于保存.传递数据,使得数据更易于加密和压缩. .NET内建了出色的序列化和反序列化支 ...
- C# 运行时序列化
一. 序列化与反序列的作用 为什么要有序列化呢,考虑下面这种情况,在WINFORM或者更为方便的WPF工程中,当我们进行UI设计时,可以随意的将一个控件剪切/张贴到另外一个地方.操作方便的背后是什么在 ...
- (47)C#运行时序列化
序列化是将对象或对象图转化成字节流的过程.反序列化是将字节流转换回对象图的过程.
- 混合语言编程:启用CLR(公共语言运行时编译)让C#调用C++
前言 关于混合C#和C++的编程方式,本人之前写过一篇博客(参见混合语言编程:C#使用原生的Directx和OpenGL),在之前的博客中,介绍了在C#的Winform和WPF下使用原生的Direct ...
- [CLR via C#]4. 类型基础及类型、对象、栈和堆运行时的相互联系
原文:[CLR via C#]4. 类型基础及类型.对象.栈和堆运行时的相互联系 CLR要求所有类型最终都要从System.Object派生.也就是所,下面的两个定义是完全相同的, //隐式派生自Sy ...
随机推荐
- 解决android sdk无法更新 更新慢的问题
使用不同平台开发android应用的时候都要先搭建开发环境. 这里介绍一下搭建开发环境过程中更新和下载android sdk的一种方法: 第一步:配置android sdk manager的代理服务, ...
- [bzoj1297] [洛谷P4159] [SCOI2009] 迷路
Description windy在有向图中迷路了. 该有向图有 N 个节点,windy从节点 0 出发,他必须恰好在 T 时刻到达节点 N-1. 现在给出该有向图,你能告诉windy总共有多少种不同 ...
- 如何修改win7文件夹的显示方式为详细信息
1.首先对着空白处,鼠标右键单击,然后点击“排列方式” 选一个 还有 你还可以点击“查看” 选择图标大小.详细信息.平铺.列表 等2.点击我的电脑左上角的 组织 按钮 随后选择“文件夹和搜索选项” 再 ...
- 看透Spring MVC:源代码分析与实践 (Web开发技术丛书)
第一篇 网站基础知识 第1章 网站架构及其演变过程2 1.1 软件的三大类型2 1.2 基础的结构并不简单3 1.3 架构演变的起点5 1.4 海量数据的解决方案5 1.4.1 缓存和页面静态化5 1 ...
- ios---运用MJRefresh组件设置下拉刷新
#import "XMGTopicViewController.h" #import <AFNetworking.h> #import <MJExtension. ...
- kali linux下的部分命令
查看发行版本 cat /etc/issue cat /etc/*-release 查看内核版本 uname -a 显示机器的处理器架构 arch uname -m 清屏 clear 命令行 ...
- docker学习笔记1认识docker
简介 Docker是一个开源的应用容器,开发者可以打包其应用以及依赖到一个可移植的容器当中.当然容器与容器之间不存在任何接口,完全独立.最大程度的解决了我的软件只能不能在你的电脑上运行的尴尬局面.开发 ...
- 利用AppMetrics对Web进行监控教程
利用AppMetrics对Web进行监控教程 一.基础准备 1. 安装依赖 这里可以通过nuget或使用命令行进行安装,具体需要安装的类库如下(注意版本): Install-Package App.M ...
- 如何写出优雅的Python代码?
有时候你会看到很Cool的Python代码,你惊讶于它的简洁,它的优雅,你不由自主地赞叹:竟然还能这样写.其实,这些优雅的代码都要归功于Python的特性,只要你能掌握这些Pythonic的技巧,你一 ...
- sublime: javascript/css 的格式化
Sublime Text 3 破解版 + 注册机 + 汉化包 + 教程 http://www.xiumu.org/note/sublime-text-3.shtml 1.sublime 如果控制菜单选 ...