Dotnet 4.0

Jul 29, 2010 at 9:33 PM
Hi James, Do you have a fork or branch for dotnet 4.0? I have upgraded my project and fixed a few of the tests to pass for dotnet 4.0 and thought it would be good to contribute them back somewhere. Cheers Simon
Coordinator
Aug 2, 2010 at 1:35 AM

Not yet. The next release will be .NET 3.5 but after that I'll likely upgrade the solution to VS2010.

 

Aug 9, 2010 at 5:04 PM

In .NET 4 we got something called ExpandoObject which is part of the dynamic framework. I think it would make lot of sense to unserialize a JSON object graph into an object graph of ExpandoObjects.

ExpandoObjects properties are also WPF bindable.

Just FYI. 

Aug 9, 2010 at 10:04 PM
Hi Marten, That sounds very interesting. I guess it means you don't have to know or have a target type on the server side. Also on a similar note I have extended the javascript json parser at http://www.json.org/json2.js to deserialize entity references generated by Json.NET and would be happy to share this if anyone needs this functionality. I was able to find this functionality (easily) else where. Cheers Simon
Aug 10, 2010 at 4:56 AM

Would love to see a method to convert JObject to ExpandoObject.

Aug 10, 2010 at 12:13 PM

Exactly, you don't have to have a specific type that matches the JSON object as ExpandoObject are a IDictionary<string,object>. This also means that they are very easy to populate:

         dynamic expando = new ExpandoObject();

         IDictionary<string, object> expandoDictionary = expando;
         expandoDictionary["Test"] = "My property";

         Console.WriteLine(expando.Test);

As mentioned WPF bindings also works which is uber (ExpandoObject implements INotifyPropertyChanged):

{Binding Path=Test}

 

 

 


Aug 10, 2010 at 12:52 PM

For those that are interested I wrote up a very easy routine to traverse the json object graph and build an ExpandoObject graph. As I don't know the JSON.NET API that well I might have made some serious blunders.

static readonly object s_endObject = new object();
static readonly object s_endArray = new object();

static object FromJsonArrayValue(JsonReader jsonReader)
{
   object value;
   var list = new List<object>();
   while (!ReferenceEquals(value = FromJsonValue(jsonReader), s_endArray))
   {
      list.Add(value);
   }
   return list.ToArray();
}

static object FromJsonObjectValue(JsonReader jsonReader)
{
   object name;
   object value;
   IDictionary<string, object> expando = new ExpandoObject();
   while (
         !ReferenceEquals(name = FromJsonValue(jsonReader), s_endObject) 
      && !ReferenceEquals(value = FromJsonValue(jsonReader), s_endObject)
      )
   {
      expando[name.ToString()] = value;
   }
   return expando;
}

static object FromJsonValue(JsonReader jsonReader)
{
   if (!jsonReader.Read())
   {
      return null;
   }

   switch (jsonReader.TokenType)
   {
      case JsonToken.None:
      case JsonToken.Null:
         return null;

      case JsonToken.StartObject:
         return FromJsonObjectValue(jsonReader);

      case JsonToken.StartArray:
         return FromJsonArrayValue(jsonReader);

      case JsonToken.StartConstructor:
      case JsonToken.Comment:
      case JsonToken.EndConstructor:
         return null;

      case JsonToken.PropertyName:
      case JsonToken.Raw:
      case JsonToken.Integer:
      case JsonToken.Float:
      case JsonToken.String:
      case JsonToken.Boolean:
      case JsonToken.Date:
      case JsonToken.Bytes:
         return jsonReader.Value;

      case JsonToken.EndObject:
         return s_endObject;

      case JsonToken.EndArray:
         return s_endArray;
   }
   throw new ArgumentOutOfRangeException();
}

static dynamic FromJson(string s)
{
   using (var stringReader = new StringReader(s))
   using (var reader = new JsonTextReader(stringReader))
   {
      return FromJsonValue(reader);
   }
}

Aug 13, 2010 at 9:56 PM
Edited Aug 15, 2010 at 6:23 PM

Instead of parsing into ExpandoObjects, why not update the existing JToken object hierarchy to support the new IDynamicMetaObjectProvider interface? ExpandoObject is just an implementation of IDMOP provided by the framework. All the new dynamic features work against the low-level IDynamicMetaObjectProvider under the hood.

.NET 4.0 also includes DynamicObject, which is sort of a middle ground between ExpandoObject and IDynamicMetaObjectProvider, but since the Json.NET LINQ objects already have parent classes, you can't use DynamicObject.

I acually hacked up the JSON LINQ objects with IDynamicMetaObjectProvider in order to support dynamic get support a few days ago. It lets me write code like this:

dynamic user = JObject.Parse(twitter_user_json);

string screen_name = user.screen_name;
bool following = user.following;
long tweet_id = user.status.id;

No more field names in strings, no more square brackets, no more explicit casts.

Would be happy to provide a patch. I've updated JObject, JArray and JValue (with stubbed out placeholders for JConstructor and JProperty). it's actually not that tough to add - a little reflection + expression code is all you need. Here's what JObject looks like with IDMOP support:

public class JObject : JContainer, IDictionary<string, JToken>, INotifyPropertyChanged
#if !PocketPC && !SILVERLIGHT && !NET20
    , INotifyPropertyChanging
#endif
#if DYNAMIC
   , IDynamicMetaObjectProvider
#endif
{
#if DYNAMIC
    private class JObjectMetaObject : DynamicMetaObject
    {
        public JObjectMetaObject(Expression parameter, JObject jObject) 
            : base(parameter, BindingRestrictions.Empty, jObject)          
        {
        }

        public override DynamicMetaObject BindGetMember(GetMemberBinder binder)
        {
            var method = typeof(JObject).GetProperty("Item", new Type[] { typeof(string) }).GetGetMethod();
            var parameters = new Expression[] { Expression.Constant(binder.Name) };

            return new DynamicMetaObject(
                Expression.Call(
                  Expression.Convert(Expression, LimitType),
                  method, parameters),
                BindingRestrictions.GetTypeRestriction(Expression, LimitType));
        }
    }
    
    //this is the one method required by IDynamicMetaObjectProvider
    public DynamicMetaObject GetMetaObject(Expression parameter)
    {
        return new JObjectMetaObject(parameter, this);
    }
#endif //DYNAMIC

//remaining JObject code remains unchanged