Dan Newcome, blog

I'm bringing cyber back

Method_missing in C#

with 3 comments

There have been a lot of instances where I wanted to intercept any call to an object in C#. In dynamic languages like Ruby, this is pretty easy, since there is a catch-all method that gets called if no method exists. This method is method_missing.

Now that C# supports the dynamic keyword and the framework supplies a dynamic object base class, we can now emulate method_missing.

One of the things I want in C# is a Javascript-like hash object that can be accessed like a dictionary or like a property bag using either property or indexer syntax. Phil Haack covered an early usage of DynamicObject here, and later the .NET framework included a type called ExpandoObject which allows the use of property accessor syntax for adding attributes dynamically.

However, I wanted to be able to use the indexer syntax in addition to property syntax. The only way to do this with ExpandoObject is to cast to Dictionary and access the items using IDictionary methods like this:

ExpandoObject expando = new ExpandoObject();
((IDictionary)expando).Add("theanswer", 42);

This is unnecessarily messy so I rolled my own ExpandoObject based on Phil’s code that allows indexer access to its members. Here is what I came up with:

using System;
using System.Collections.Generic;
using System.Dynamic;

public class SuperSpando : DynamicObject {

	Dictionary<string, object> 
		m_store = new Dictionary<string, object>();

	public object this[ string key ] {
		get {
			return m_store[ key ];
		}
		set {
			m_store[ key ] = value;
		}	
	}	
	  public override bool TrySetMember(SetMemberBinder binder, object value) {
	   m_store[ binder.Name ] = value;
	    return true;
	  }

	  public override bool TryGetMember(GetMemberBinder binder, 
	      out object result) {
	    return m_store.TryGetValue(binder.Name, out result);
	  }
} // class

Here is a sample use case showing both access methods:

dynamic ss = new SuperSpando();

// normal assignment works for ExpandoObject also
ss.foo = "bar";

// can't do this with ExpandoObject
ss["baz"]= "spaz";

Console.WriteLine( ss["foo"]);
Console.WriteLine( ss.baz );
Console.ReadLine();

Later on I might have to databind SuperSpando. I’m messing with a few reflection-based methods of doing this, but it looks like using DataTable might be the best way to do it. Seems ugly to me, but then so does using reflection.

Advertisements

Written by newcome

June 5, 2011 at 11:34 am

Posted in Uncategorized

3 Responses

Subscribe to comments with RSS.

  1. I remember doing something similar for reading data rows and stuff. Also if you store everything in a datarow instead of a dictionary, then I’m not sure about read time, but u can also use the datarows generic “Field” method and get typed objects back.
    http://www.codeproject.com/KB/cs/DynamicDataRowExtensions.aspx

    vshlos

    June 9, 2011 at 7:48 pm

  2. I’ve done a lot with WPF data-binding dynamic objects. I have an opensource framework ImpromptuInterface that has a lot of c# dynamic niceties in it.
    http://code.google.com/p/impromptu-interface

    It has an ImpromptuDictionary dynamic type and it works similar to yours above and implements INotifyPropertyChanged.
    http://code.google.com/p/impromptu-interface/wiki/UsageDynamic

    That will get you most of the way binding for controls, unless you want autogenerated columns on a DataGrid. DataGrids get their autogenerated columns from the enumerable container, so in the MVVM specific classes i have a ImpromptuBindingList that will try to figure out that dynamic column paths based on the first object, but also has delegate hooks so you can provide them yourself.

    It all works really well and so I have an MVVM ViewModel implementation sub-classed from ImpromptuDictionary that provides boilerplate free command and event binding a long with the properties.
    http://code.google.com/p/impromptu-interface/wiki/UsageMVVM

    jbtule

    June 29, 2011 at 1:54 pm

  3. @jay Thanks looks cool, I’ll check it out.

    newcome

    June 29, 2011 at 6:12 pm


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: