JavaScriptSerializer.cs
上传用户:szgaoree
上传日期:2009-01-05
资源大小:74k
文件大小:7k
- /*
- * MS 06-04-03 fixed Decimal value, now using double instead
- * MS 06-04-04 added enum as integer instead of returning a class
- *
- *
- *
- */
- using System;
- using System.Text;
- using System.Reflection;
- namespace AjaxPro
- {
- /// <summary>
- /// Provides methods for serializing .NET objects to Java Script Object Notation (JSON).
- /// </summary>
- public class JavaScriptSerializer
- {
- /// <summary>
- /// Converts a .NET object into a JSON string.
- /// </summary>
- /// <param name="o">The object to convert.</param>
- /// <returns>Returns a JSON string.</returns>
- /// <example>
- /// using System;
- /// using AjaxPro;
- ///
- /// namespace Demo
- /// {
- /// public class WebForm1 : System.Web.UI.Page
- /// {
- /// private void Page_Load(object sender, System.EventArgs e)
- /// {
- /// DateTime serverTime = DateTime.Now;
- /// string json = JavaScriptSerializer.Serialize(serverTime);
- ///
- /// // json = "new Date(...)";
- /// }
- /// }
- /// }
- /// </example>
- public static string Serialize(object o)
- {
- JavaScriptSerializer js = new JavaScriptSerializer();
- return js.SerializeInternal(o);
- }
- /// <summary>
- /// Converts a string into a JSON string.
- /// </summary>
- /// <param name="s">The string to convert.</param>
- /// <returns>Returns a JSON string.</returns>
- public static string SerializeString(string s)
- {
- JavaScriptSerializer js = new JavaScriptSerializer();
- return js.SerializeInternal(s);
- }
- #region Internal Methods
- internal string SerializeInternal(object o)
- {
- StringBuilder sb = new StringBuilder();
- this.SerializeValue(o, sb);
- return sb.ToString();
- }
- internal void SerializeString(string s, StringBuilder sb)
- {
- sb.Append(""");
- sb.Append(JavaScriptUtil.QuoteString(s));
- sb.Append(""");
- }
- internal void SerializeDecimal(Decimal d, StringBuilder sb)
- {
- // this.SerializeValue(Decimal.GetBits(d), sb);
- // The following code is not correct, but while JavaScript cannot
- // handle the decimal value correct we are using double instead.
- this.SerializePrimitive((double)d, sb);
- }
- internal void SerializeBoolean(bool b, StringBuilder sb)
- {
- sb.Append((b ? "true" : "false"));
- }
- internal void SerializePrimitive(object o, StringBuilder sb)
- {
- if(o is char || o is byte || o is sbyte)
- {
- sb.Append(o.ToString());
- return;
- }
- if(o is float && ((float)o) == float.NaN)
- {
- throw new ArgumentException("object must be a valid number (float.NaN)", "number");
- }
- if(o is double && ((double)o) == double.NaN)
- {
- throw new ArgumentException("object must be a valid number (double.NaN)", "number");
- }
- // Shave off trailing zeros and decimal point, if possible
- string s = o.ToString().ToLower().Replace(System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator, ".");
- if(s.IndexOf('e') < 0 && s.IndexOf('.') > 0)
- {
- while(s.EndsWith("0"))
- {
- s.Substring(0,s.Length-1);
- }
- if (s.EndsWith("."))
- {
- s.Substring(0,s.Length-1);
- }
- }
-
- sb.Append(s);
- }
- internal void SerializeArray(Array a, StringBuilder sb)
- {
- bool b = true;
- sb.Append("[");
- foreach(object o in a)
- {
- if(b){ b = false; }
- else{ sb.Append(","); }
- this.SerializeValue(o, sb);
- }
- sb.Append("]");
- }
- internal void SerializeCustomObject(object o, StringBuilder sb)
- {
- AjaxNonSerializableAttribute[] nsa = (AjaxNonSerializableAttribute[])o.GetType().GetCustomAttributes(typeof(AjaxNonSerializableAttribute), true);
- bool b = false;
- sb.Append('{');
-
- sb.Append(""__type":");
- this.SerializeString(o.GetType().AssemblyQualifiedName, sb);
-
- FieldInfo[] fields = o.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance);
- for(int i=0; i<fields.Length; i++)
- {
- FieldInfo fi = fields[i];
- if((nsa.Length > 0 && fi.GetCustomAttributes(typeof(AjaxPropertyAttribute), true).Length > 0) ||
- (nsa.Length == 0 && fi.GetCustomAttributes(typeof(AjaxNonSerializableAttribute), true).Length == 0))
- {
- if(b){ b = false; }
- else{ sb.Append(','); }
- this.SerializeString(fi.Name, sb);
- sb.Append(':');
- this.SerializeValue(fi.GetValue(o), sb);
- }
- }
- b = false;
- PropertyInfo[] properties = o.GetType().GetProperties(BindingFlags.GetProperty | (BindingFlags.Public | BindingFlags.Instance));
- for(int i=0; i<properties.Length; i++)
- {
- PropertyInfo prop = properties[i];
- MethodInfo mi = prop.GetGetMethod();
- if (mi.GetParameters().Length <= 0)
- {
- if((nsa.Length > 0 && mi.GetCustomAttributes(typeof(AjaxPropertyAttribute), true).Length > 0) ||
- (nsa.Length == 0 && mi.GetCustomAttributes(typeof(AjaxNonSerializableAttribute), true).Length == 0))
- {
- if(b){ b = false; }
- else{ sb.Append(","); }
- this.SerializeString(prop.Name, sb);
- sb.Append(':');
- this.SerializeValue(mi.Invoke(o, null), sb);
- }
- }
- }
- sb.Append('}');
- }
- internal void SerializeValue(object o, StringBuilder sb)
- {
- if(o == null || o is System.DBNull)
- {
- sb.Append("null");
- }
- else if(o is string)
- {
- this.SerializeString((string)o, sb);
- }
- else if(o is char)
- {
- this.SerializeString(o.ToString(), sb);
- }
- else if(o is bool)
- {
- this.SerializeBoolean((bool)o, sb);
- }
- #if(NET20)
- //else if (o is Nullable)
- //{
- //}
- #endif
- else if (o.GetType().IsPrimitive)
- {
- this.SerializePrimitive(o, sb);
- }
- else if (o.GetType().IsEnum)
- {
- this.SerializePrimitive((int)o, sb);
- }
- else if (o is Guid)
- {
- this.SerializeString(o.ToString(), sb);
- }
- else if (o is Decimal)
- {
- this.SerializeDecimal((Decimal)o, sb);
- // sb.Append(o.ToString());
- }
- else if (o is Exception)
- {
- Exception ex = (Exception)o;
- sb.Append("null; r.error = {"Message":");
- this.SerializeString(ex.Message, sb);
- sb.Append(","Type":");
- this.SerializeString(o.GetType().FullName, sb);
- if (AjaxPro.Utility.Settings.DebugEnabled)
- {
- sb.Append(","Stack":");
- this.SerializeString(ex.StackTrace, sb);
- sb.Append(","TargetSite":");
- this.SerializeString(ex.TargetSite.ToString(), sb);
- sb.Append(","Source":");
- this.SerializeString(ex.Source, sb);
- }
- sb.Append("}");
- }
- else
- {
- JavaScriptConverterAttribute[] attr = (JavaScriptConverterAttribute[])o.GetType().GetCustomAttributes(typeof(JavaScriptConverterAttribute), false);
- if (attr.Length > 0)
- {
- sb.Append(attr[0].Converter.Serialize(o));
- return;
- }
- IJavaScriptConverter c = JavaScriptConverter.GetSerializableConverter(o.GetType());
- if (c != null)
- {
- sb.Append(c.Serialize(o));
- return;
- }
- if (o.GetType().IsArray)
- {
- this.SerializeArray((Array)o, sb);
- }
- else
- {
- this.SerializeCustomObject(o, sb);
- }
- }
- }
- #endregion
- }
- }