I had just been playing around with C# 3.0 extension methods when Scott Hanselman posted this article about easy JSON object serialization in Ruby. That got me thinking that with .NET Reflection and C# 3.0 extension methods, this should be easy to do in C#. Here is what I came up with:
using System;
using System.Text;
using System.Reflection;
namespace KeithHill.CSharpExtensionMethodSample {
public class Person {
public string firstName = "Scott";
public string lastName = "Hanselman";
public DateTime birthDay = DateTime.Parse("1:1:0 1/15/1970");
public decimal moneyInPocket = 4.5M;
}
class Program {
static void Main(string[] args) {
Person person = new Person();
Console.WriteLine(person.ToJavaScriptObjectNotation());
}
}
public static class JsonExtension {
public static string ToJavaScriptObjectNotation(this object obj) {
var strBld = new StringBuilder("{");
Type objType = obj.GetType();
bool firstIter = true;
foreach (FieldInfo fieldInfo in
objType.GetFields(BindingFlags.Public | BindingFlags.Instance)) {
if (!firstIter) strBld.Append(", ");
strBld.AppendFormat("\"{0}\":{1}", fieldInfo.Name,
GetJsonStringForFieldValue(fieldInfo, obj));
firstIter = false;
}
strBld.Append("}");
return strBld.ToString();
}
private static string GetJsonStringForFieldValue(FieldInfo field, object obj) {
string val;
string typeName = field.FieldType.FullName;
switch (typeName) {
case "System.DateTime":
TimeSpan ts = (DateTime)field.GetValue(obj) - DateTime.Parse("1/1/1970");
val = " new Date(" + ts.TotalMilliseconds.ToString() + ")";
break;
case "System.String":
val = "\"" + (string)field.GetValue(obj) + "\"";
break;
default:
val = field.GetValue(obj).ToString();
break;
}
return val;
}
}
}
Now this is by no means bullet proof. Heck I only spent about 15 minutes on it and most of that time was figuring out how the heck to convert a .NET DateTime to a JavaScript Date value. Anyway the output looks like this:
{"firstName":"Scott", "lastName":"Hanselman",
"birthDay": new Date(1213260000), "moneyInPocket":4.5}
"birthDay": new Date(1213260000), "moneyInPocket":4.5}
How can I compile this code?
Michael, you need to download the May CTP LINQ bits. Those bits contain the early preview of the C# 3.0 compiler that supports extension methods. The bits can be downloaded here:
http://www.microsoft.com/downloads/details.aspx?FamilyID=1E902C21-340C-4D13-9F04-70EB5E3DCEEA&displaylang=en
I just ran across Scott Hanselman\’s post and had the same idea of leveraging extension methods… Luckily I googled first before coding 🙂
You might want to plug a \’real\’ JSON serializer (such as Atlas) into the extension method to support more nested or more complex datatypes, etc. The code as it stands is a great proof of concept but isn\’t really robust enough for real world scenarios.
Addys, I really don\’t know enough about JSON to go much further. I just thought, like you did, that C# 3.0 extension methods should enable this scenario.
It\’s even easier now using the DataContractJsonSerializer class…
public static string ToJSON( this object obj )
{
string json = string.Empty;
DataContractJsonSerializer ser = new DataContractJsonSerializer(obj.GetType());
using ( MemoryStream ms = new MemoryStream() )
{
ser.WriteObject(ms, obj);
json = Encoding.Default.GetString(ms.ToArray());
}
return json;
}
And to get back…
public static T FromJSON<T>( this string json )
{
using ( MemoryStream ms = new MemoryStream(ASCIIEncoding.Default.GetBytes(json)) )
{
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(T));
return (T)ser.ReadObject(ms);
}
}
That\’s a new feature in WCF in .NET 3.5, right? I\’ll have to look into that. Thanks for the sample code!