Cook Computing

Alternative Syntax for Member Calls on C# Dynamic Types

May 27, 2009 Written by Charles Cook

XML-RPC.NET is essentially concerned with making statically typed calls to XML-RPC endpoints, using interfaces as contract definitions in a similar way to WCF. However the new dynamic type in .NET 4 makes it possible to provide a clean way of making dynamically typed calls, for example like this:


dynamic client = new XmlRpcClient("http://someXmlRpcEndpont");
int returnValue = client.Add(2, 3);

The DynamicObject class in the System.Dynamic namespace makes implementing a dynamic class straightforward:


using System.Dynamic;

class XmlRpcClient : DynamicObject
{
  string endpoint;

  public XmlRpcClient(string endpoint)
  {
    this.endpoint = endpoint;
  }

  public object Invoke(string methodName, object[] args)
  {
    return 5; // actually make call to XML-RPC endpoint here
  }

  public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, 
    out object result)
  {
    result = Invoke(binder.Name, args);
    return true;
  }
}

However, the method name in XML-RPC can be an arbitrary string which is not necessarily representable as a token in C#, for example "samples.Add". JavaScript handles this case by providing an alternative syntax to access a member via a string and then make a call on it, for example:


obj["foo"]()    // get member 'foo' and call it

The dynamic type of C# does not support this, at least in the current beta, but it can be implemented:


using System.Dynamic;

class XmlRpcClient : DynamicObject
{
  // ... 

  public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, 
    out object result)
  {
    result = (Func)(args => Invoke(indexes[0] as string, args));
    return true;
  }

  public delegate object Func(params object[] args);
}

So making this code possible:


dynamic client = new XmlRpcClient("http://someXmlRpcEndpont");
int returnValue = client["samples.Add"](2, 3);