Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Dynamic Binding in C#

0.00/5 (No votes)
4 Feb 2011 1  
Illustrates a dynamic binding implementation in C#

Introduction

This article will show you how to simulate dynamic binding in C#.

Background

To understand the meaning of dynamic binding, one can look at SRFI 39 which is an implementation of a dynamic binding mechanism for the R5RS Scheme. Dynamic binding is also frequently used in LISP. Another commonly used dynamic binding is the 'this' keyword in JavaScript. For an in-depth explanation, please read chapter 2 of LISP in Small Pieces by Christian Queinnec.

To understand what this code does (in terms of dynamic binding), consider the following pseudo C# snippet:

var orig-value = getvalue(location);
setvalue(location, new-value);
try
{
  body
}
finally
{
  setvalue(location, orig-value);
}

Firstly, it gets the original value, which is stored. Then it sets the value at the location (property or field or a getter/setter method pair) to the new value. Once the execution leaves the body part, the original value is restored unconditionally. This means even in the presence of exceptions, the value is faithfully restored.

Another aspect is the fact that dynamic bindings can be nested within one another. For example, we can place the same construct within the body part.

This illustrates the essence of dynamic binding, and how it is implemented in the code complementing this article.

Using the Code

The code is in the form of Extension Methods that are encapsulated in a single class. To use the code, you can copy the class anywhere and simply include the containing namespace.

The 'API' exposes two methods with two overloads each.

The Bind method does a plain dynamic binding, while the With method allows the dynamic binding to be disposed automatically when exiting the body of the dynamic binding. Both methods should be called in the expression part of the using construct in C#.

Use the following as a guide to the terminology used above and throughout the article:

using (expression)
{
  body
}

Each of the above methods provides an additional overloaded method taking an Expression<Func<T>> argument for convenience. This allows one to build getter and setter delegates for both properties and fields.

Here follows the method signatures and documentation for the exposed methods:

/// <summary>
/// Binds newvalue with getter and setter delegates
/// </summary>
/// <typeparam name="T">Inferred</typeparam>
/// <param name="newvalue">the newvalue to bind</param>
/// <param name="getter">delegate to get the value</param>
/// <param name="setter">delegate to set the value</param>
/// <returns>an instance to wrap use in a using construct</returns>
public static IDisposable Bind<T>(this T newvalue, Func<T> getter, Action<T> setter)
/// <summary>
/// Binds newvalue with get/set property
/// </summary>
/// <typeparam name="T">Inferred</typeparam>
/// <param name="newvalue">the newvalue to bind</param>
/// <param name="locator">the locator,
/// must be in the form () => instance.Property or () => Type.Property</param>
/// <returns>an instance to wrap use in a using construct</returns>
public static IDisposable Bind<T>(this T newvalue, Expression<Func<T>> locator)
/// <summary>
/// Binds newvalue with getter and setter delegates and
/// disposes the value when exiting the using construct
/// </summary>
/// <typeparam name="T">Inferred, must be IDisposable</typeparam>
/// <param name="newvalue">the newvalue to bind</param>
/// <param name="getter">delegate to get the value</param>
/// <param name="setter">delegate to set the value</param>
/// <returns>an instance to wrap use in a using construct</returns>
public static IDisposable With<T>(this T newvalue, Func<T> getter, 
              Action<T> setter) where T : IDisposable
/// <summary>
/// Binds newvalue with get/set property and disposes
/// the value when exiting the using construct
/// </summary>
/// <typeparam name="T">Inferred, must be IDisposable</typeparam>
/// <param name="newvalue">the newvalue to bind</param>
/// <param name="locator">the locator, must be in the form
/// () => instance.Property or () => Type.Property</param>
/// <returns>an instance to wrap use in a using construct</returns>
public static IDisposable With<T>(this T newvalue, 
       Expression<Func<T>> locator) where T : IDisposable

Usage Examples

The attached code contains several examples to illustrate the usage of this dynamic binding implementation. In each of the examples, the original value will be restored after exiting the using construct's body.

The following class declaration will be used in some of the examples:

class TestClass
{
  public string Test { get; set; }
  public static object StaticField;
}

Instance Property Example

var tc = new TestClass { Test = "Foo" };

Console.WriteLine(tc.Test);

using ("Bar".Bind(() => tc.Test))
{
  Console.WriteLine(tc.Test);

  using ("Baz".Bind(() => tc.Test))
  {
    Console.WriteLine(tc.Test);
  }

  Console.WriteLine(tc.Test);
}

Console.WriteLine(tc.Test);

Static Property Example

Console.WriteLine(Console.ForegroundColor);

using (ConsoleColor.Red.Bind(() => Console.ForegroundColor))
{
  Console.WriteLine(Console.ForegroundColor);
}

Console.WriteLine(Console.ForegroundColor);

Local Variable Example

var i = 0;

Console.WriteLine(i);

using (10.Bind(() => i))
{
  Console.WriteLine(i);
}

Console.WriteLine(i);

Static Field Example

Console.WriteLine(TestClass.StaticField);

using (10.Bind(() => TestClass.StaticField))
{
  Console.WriteLine(TestClass.StaticField);
}

Console.WriteLine(TestClass.StaticField);

Getter and Setter Method Pair Example with Sample Extension

This example makes use of a helper extension method called AsConsoleOutput():

/// <summary>
/// Redirects Console output temporarily within the using construct; can be nested
/// </summary>
/// <typeparam name="T">Inferred, must be TextWriter</typeparam>
/// <param name="writer">the writer to use</param>
/// <returns>an instance to wrap use in a using construct</returns>
public static IDisposable AsConsoleOutput<T>(this T writer) where T : TextWriter
{
  return writer.With(() => Console.Out, Console.SetOut);
}

Usage is then:

Console.WriteLine("Console");

using (File.CreateText("warning.txt").AsConsoleOutput())
{
  Console.WriteLine("Warning");

  using (File.CreateText("error.txt").AsConsoleOutput())
  {
    Console.WriteLine("Error");
  }

  Console.WriteLine("Warning");
}

Console.WriteLine("Console");

Points of Interest

The implementation makes heavy use of LINQ Expressions, and DynamicMethod from System.Reflection.Emit for performance reasons.

The implementation is only 152 lines long, including the XML documentation comments, liberal whitespace, and error checking.

Incidentally, Tomas Petricek of F# fame just posted an implementation of this in F# today after I 'announced' my intentions. The snippet can be viewed @ http://www.fssnip.net/2s. Please note that I blatantly stole his ConsoleColor example :).

History

  • 4th February, 2011: Initial version

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here