Dan Newcome, blog

I'm bringing cyber back

C# object literal notation

with 5 comments

I have a project coming up where I’d like to be able to write some declarative configuration in an object literal notation similar to JSON. The project is going to be written in C#, so I could embed a Javascript implementation like IronJS and just use JSON, or I could try using IronPython or some other .NET language that supports object literals. However, now that C# supports anonymous types, I wondered how far I could go staying within the C# language.

For starters, a simple “hash” style object can be created like so:

var obj = new { name = "value" };

Fortunately, anonymous types may be nested, so the following is valid:

var obj = new { 
    name = "value", 
    obj = new { 
        name = "value" 
    }
};

So far, things are looking pretty good. With the exception of the ‘new’ keyword, there are only slight syntactic differences between what we’d see in a JSON literal and what we have here in C#. The other major feature of JSON is the array literal. C# supports array initialization lists, so we can create a new unnamed array as such:

new object[]{ "one", "two", 3 }

Now it isn’t too much of a stretch to see that we can create arrays as values in our anonymous types, like this:

var obj = new { 
    name = "value", 
    arr = new object[] { "one", "two", 3 } 
};

Now what happens if we want go the other way around, and create an array of anonymous types? We can do this:

var obj = new object[] {
    new { name = "value" },
    new { name = "value2" }
};

There is one problem with this however. Since we are defining our array type as object, trying to access the ‘name’ member like this:

obj[1].name

Results in the following error:

error CS1061: 'object' does not contain a definition for 'name' and no extension method 'name' accepting
   a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?)

Fortunately we can make use of the ‘dynamic’ keyword (it is actually a type too!) in C# to defer static type checking on our objects by declaring the array like this:

var obj = new dynamic[] {
    new { name = "value" },
    new { name = "value2" }
};

Things are looking pretty rosy right now — sure, the added syntax is a bit of a drag compared to JSON, but so far we’ve done much less work than we would had we embedded another language.

There is one last piece to the puzzle — functions. C# supports anonymous functions in the form of either anonymous delegates or lambda functions. Either will work for our purposes here, although lambdas weren’t introduced until later, so it is possible that your version of the .NET framework won’t support them.

// using anonymous delegate
new Action( delegate() { 
    Console.WriteLine( "called function" ); 
})

// using lambda expression
new Action( () => { 
    Console.WriteLine( "called function" ); 
})

There is one trick here that I haven’t talked about yet: the Action delegate type. It turns out that an anonymous delegate or lambda expression can’t be directly assigned to a variable in our anonymous types, so we have to wrap them in a proper delegate instance. We could have created our own delegate type for this purpose, but .NET has a few built-ins that make our lives somewhat simpler. ‘Action’ is a delegate describes a function taking no parameters and returning void, perfect for our sample here which only produces the side effect of console output.

If we put everything together we can create complex objects like the following:

var obj = new { 
	name = "value", 
	function = new Action(() => { 
		Console.WriteLine( "called function" ); 
		string foo = "bar";
		var nested = new Action( () => { 
			Console.WriteLine( "inner function " + foo ); 
		});
		nested();
        },
	array = new dynamic[] { 
		"one", 
		"two",  
		new Action( () => { Console.WriteLine( "array function" ); } ),
		3
	}
};

Notice that I threw in an extra treat — there is a function called ‘nested’ nested inside of another function. The local variable ‘foo’ is visible to the nested function. Speaking of variables, this leads us to the biggest shortcoming that I’ve found with expressing object literals in C# — we have no access to the ‘this’ reference in our functions. In JSON we would be able to refer to the object instance in which the function is defined but in C# we do not. It may be possible to retrieve a reference to ‘this’ somehow using Reflection, so if some astute reader finds a method for doing so, I’d love to know about it.

About these ads

Written by newcome

June 11, 2010 at 5:05 pm

Posted in Uncategorized

5 Responses

Subscribe to comments with RSS.

  1. [...] a comment » A few days ago, I wrote a post dealing with literal data structures in .NET with a vague allusion to using them to do some [...]

  2. I’m a C# newbie so I won’t take a shot at implementing this myself, yet I feel certain that Python’s (admittedly kludgey) solution could be ported here.

    So here’s my idea: Define a new delegate class named Lambda which takes an object and a lambda as its constructor arguments and, when a Lambda instance is called, passes the object as the only argument to the passed-in lambda. Then your snippet can become (using `self’ rather than `this’ as a tribute to Python).

    var obj = new {
    	name = "value",
    	function = new Lambda( obj, (self) => {
    		Console.WriteLine( "called function" );
    		string foo = "bar";
    		var nested = new Lambda( self, (self) => {
    			foreach( var o in self.array ){
    				Console.WriteLine( "inner function " + o.ToString() );
    			}
    		});
    		nested();
            },
    	array = new dynamic[] {
    		"one",
    		"two",
    		new Lambda( obj, (self) => { Console.WriteLine( "array function" ); } ),
    		3
    	}
    };
    

    Chris "Jesdisciple"

    March 20, 2011 at 7:46 pm

  3. @chris – Thanks for commenting, glad to see I got some people thinking about this so it is cool to see some others’ efforts.

    I looked at your suggestion briefly, but I don’t think it is going to work as you intended. When defining anonymous types, the type is not available from inside the type def since it has not been fully defined yet. So where you are referring to ‘obj’ in the creation of the Lambda object will be a compiler error. Also, declaring the variable first won’t work since we don’t have the type yet, sort of a chicken and the egg problem.

    Aside from that, Simply using a new delegate type to enclose the object instance won’t quite work, we’d need to define a new type for this, however aside from that mechanical issue the concept of enclosing ‘this’ in an object is interesting. However we still have the issue above of the incompletely specified type. This is why, intuitively, I think that some reflection tricks might be necessary to fully solve this problem.

    Looking at Python as a reference is a good insight though, and I may explore this concept more in a later post when I have some time to think about it more.

    newcome

    March 22, 2011 at 11:05 am

  4. @Dan: Yeah, that occurred to me after posting. Of course sometimes JavaScript properties are batch-defined just outside an object literal so it’s not a huge issue, but if you really want to solve it you can make a function that’s a reference to “this”/”self” which would return the proper object once the definition had been completed.

    I also revised the syntax in my thought-experiments:
    new M(object, ‘name’, (self) => {

    });
    The M delegate assigns the lambda as object.name and pass object in as self. I get tired of typing “function” in JavaScript, thus the one-letter identifier; and I chose M because it could be used as a generic assigner for all members, not just functions. Plus my Lambda instances weren’t really lambdas, since they had state.

    By the way, you should look at Clay: http://weblogs.asp.net/bleroy/archive/2010/08/16/clay-malleable-c-dynamic-objects-part-1-why-we-need-it.aspx

    Finally, I should note that this isn’t possible in Mono until version 4 (which hasn’t yet been released). :-(

    Jesdisciple

    March 22, 2011 at 4:57 pm

  5. […] an awesome blog post on how to declare literal objects and object arrays in […]


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: