Mega Code Archive

 
Categories / C# Book / 02 Essential Types
 

0339 Dynamic Objects

We can create our own dynamic type by extending the DynamicObject type. using System; using System.Dynamic; using System.Reflection; using System.Collections.Generic; public class MyDynamic: DynamicObject { public override bool TryInvokeMember( InvokeMemberBinder binder, object[] args, out object result) { Console.WriteLine(binder.Name + " method was called"); result = null; return true; } } public class Test { static void Main() { dynamic d = new MyDynamic(); d.MethodA(); d.MethodB(); } } The output: MethodA method was called MethodB method was called DynamicObject exposes other virtual methods that enable consumers to use other programming constructs as well. The following correspond to constructs that have representations in C#: Method Programming construct TryInvokeMember Method TryGetMember, TrySetMember Property or field TryGetIndex, TrySetIndex Indexer TryUnaryOperation Unary operator such as ! TryBinaryOperation Binary operator such as == TryConvert Conversion (cast) to another type TryInvoke Invocation on the object itself e.g., d("foo") The following demonstrates TryBinaryOperation and TryInvoke: using System; using System.Dynamic; using System.Xml.Linq; using System.Reflection; using System.Collections.Generic; public class Duck : DynamicObject { public override bool TryBinaryOperation(BinaryOperationBinder binder, object arg, out object result) { Console.WriteLine(binder.Operation); result = "foo"; return true; } public override bool TryInvoke(InvokeBinder binder, object[] args, out object result) { Console.WriteLine(args[0]); result = 123; return true; } } public class Test { static void Main() { dynamic d = new Duck(); Console.WriteLine(d + d); Console.WriteLine(d(78, 'x')); } } The output: Add foo 78 123 The following example extends the DynamicObject class to create a wrapper around a dictionary. Calls to get and set properties on the dynamic type are mapped to the key/value pairs contained in the dictionary: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Reflection; using System.Dynamic; class MainClass { static void Main(string[] args) { dynamic dynamicDict = new MyDynamicDictionary(); // Set some properties. Console.WriteLine("Setting property values"); dynamicDict.FirstName = "Adam"; dynamicDict.LastName = "Freeman"; // Get some properties. Console.WriteLine("\nGetting property values"); Console.WriteLine("Firstname {0}", dynamicDict.FirstName); Console.WriteLine("Lastname {0}", dynamicDict.LastName); // Call an implemented member. Console.WriteLine("\nGetting a static property"); Console.WriteLine("Count {0}", dynamicDict.Count); Console.WriteLine("\nGetting a non-existent property"); try { Console.WriteLine("City {0}", dynamicDict.City); } catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException e) { Console.WriteLine("Caught exception"); } } } class MyDynamicDictionary : DynamicObject { private IDictionary<string, object> dict = new Dictionary<string, object>(); public int Count { get { Console.WriteLine("Get request for Count property"); return dict.Count; } } public override bool TryGetMember(GetMemberBinder binder, out object result) { Console.WriteLine("Get request for {0}", binder.Name); return dict.TryGetValue(binder.Name, out result); } public override bool TrySetMember(SetMemberBinder binder, object value) { Console.WriteLine("Set request for {0}, value {1}", binder.Name, value); dict[binder.Name] = value; return true; } } The output: Setting property values Set request for FirstName, value Adam Set request for LastName, value Freeman Getting property values Get request for FirstName Firstname Adam Get request for LastName Lastname Freeman Getting a static property Get request for Count property Count 2 Getting a non-existent property Get request for City Caught exception