ASP.NET AJAX框架编程之JSON序列化剖析(2)
http://www.sina.com.cn 2008年04月11日 15:34
天极yesky
二、实现序列/反序列化的关键—JavaScriptSerializer
实现序列化及反序列化的对象是JavaScriptSerializer。下面,我们来具体地看一下这个对象的成员定义情况:
public class JavaScriptSerializer
{
//字段
internal const int DefaultMaxJsonLength = 0x200000;
internal const int DefaultRecursionLimit = 100;
internal const string ServerTypeFieldName = "__type";
//方法
static JavaScriptSerializer();
public JavaScriptSerializer();
public JavaScriptSerializer(JavaScriptTypeResolver resolver);
public T ConvertToType(object obj);
public T Deserialize(string input);
public object DeserializeObject(string input);
public void RegisterConverters(IEnumerable converters);
public string Serialize(object obj);
public void Serialize(object obj, StringBuilder output);
//属性
public int MaxJsonLength { get; set; }
public int RecursionLimit { get; set; }
internal JavaScriptTypeResolver TypeResolver { get; }
}
首先需要注意的是,如果嵌套的对象数目大于RecursionLimit属性中所定义的值100的话,序列化过程将会失败。显然,如果序列化后的字符串的长度超出MaxJsonLength属性所定义的值0x200000(即十进制的2,097,152)的话,序列化过程也会失败。
此外,通过上面代码也可以看出,对象将被序列化为一个StringBuilder对象,最后返回相应的字符串数据。其实,主要的工作是在私有方法SerializeValue()中完成的。在我们讨论这个方法之前,首先注意到,JavaScriptSerializer对象使用了JavaScriptTypeResolver对象。这个JavaScript类型解析器负责实现在字符串类型与其他类型之间的相互转换;当序列化定制对象时这一功能是非常重要的。还应注意的是,__type属性将被包含于JSON序列化文本中,以便标识对象的类型。之后,客户端会把JSON文本反序列化为原始的对象形式。
JavaScriptTypeResolver对象包括两个public类型的方法,一个负责把原始类型解析为字符串类型,另一个则负责把字符串解析为原始类型。这个类的原型定义如下所示:
public abstract class JavaScriptTypeResolver
{
//方法
protected JavaScriptTypeResolver();
public abstract Type ResolveType(string id);
public abstract string ResolveTypeId(Type type);
}
显然,上面这个JavaScriptTypeResolver类是一个抽象基类;因此,必须通过其他对象进一步派生使用,从而最终实现在原始类型与字符串之间的相应解析。现在,我们可以使用的对象是SimpleTypeResolver,而且它也正好实现了上面所要求实现的方法—使用System.Type对象实现字符串描述形式与原始Type对象之间的相互解析。请看下面的例子:
public override Type ResolveType(string id)
{
return Type.GetType(id);
}
public override string ResolveTypeId(Type type)
{
if (type == null)
{
throw new ArgumentNullException("type");
}
return type.AssemblyQualifiedName;
}
最后,JavaScriptSerializer对象还有可能使用JavaScriptConverter对象,因为内置的序列化过程无法实现对于所有可用数据类型的序列化。在这种情况下,可以从抽象基类JavaScriptConverter对象派生一个子类,由它来实现特定类型数据的序列/反序列化。可以使用JavaScriptSerializer对象的RegisterConverters()方法注册一个转换器对象。此方法把所有的转换器对象存储在一个Dictionary对象中;针对多种不同的数据类型的转换器经注册后都会存储在此字典对象中。概括来看,这个Dictionary对象被定义如表格1所示的一些数据类型。
表1—可序列化的数据类型汇总
|
原始数据类型 |
被序列化后的形式 |
|
null或DBNull |
"null" |
|
string |
带引号的字符串 |
|
char |
如果是‘\0’则转换为"null";否则,序列化为带引号的字符串 |
|
bool |
"true"或"false" |
|
DateTime |
"\/Date(ticks since 12:00AM 1970/01/01 UTC)\/" |
|
Guid |
“string representation”: sb.Append(""").Append(guid.ToString()).Append("""); |
|
Uri |
sb.Append(""").Append(uri.GetComponents(UriComponents.SerializationInfoString,UriFormat.UriEscaped)).Append("""); |
|
double |
sb.Append(((double) o).ToString("r", CultureInfo.InvariantCulture)); |
|
float |
sb.Append(((float) o).ToString("r", CultureInfo.InvariantCulture)); |
|
primitive或decimal |
IConvertible convertible = o as IConvertible; sb.Append(convertible.ToString(CultureInfo.InvariantCulture)); |
|
Enum |
sb.Append((int) o); |
|
IDictionary |
转换为JSON文本串,例如: {"Key1":Value1,"Key2":Value2 ... } |
|
IEnumerable |
转换为JSON文本串,例如: {"Key1":Value1,"Key2":Value2 ... } |
对于定制对象来说,它们可以按照类似于IDictionary的方式加以序列化,但仍存在一些不同之处。如果事先定义了一个JavaScriptTypeResolver对象,那么对象的类型将被转换成一个字符串,于是对象定义中会包括一个字符串常量__type,它的后面跟着的是描述对象数据类型的字符串。所有定义为public类型而且不包含元数据ScriptIgnoreAttribute属性的字段和属性都会包含在此对象的JSON对象描述之中。