Click here to Skip to main content
Click here to Skip to main content

Dynamic Binding in C#

, 4 Feb 2011 Public Domain
Rate this:
Please Sign up or sign in to vote.
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 Smile | :) .

History

  • 4th February, 2011: Initial version

License

This article, along with any associated source code and files, is licensed under A Public Domain dedication

Share

About the Author

leppie
Software Developer
South Africa South Africa
No Biography provided
Follow on   Twitter

Comments and Discussions

 
GeneralSmall bug fix for using internal/private properties Pinmemberleppie13-Feb-11 21:03 
GeneralMy vote of 5 PinmemberRaviRanjankr4-Feb-11 18:13 
GeneralMy vote of 5 PinmemberBinoy Patel4-Feb-11 12:28 
GeneralMy vote of 5 PinmemberHimanshuJoshi4-Feb-11 10:24 
Excellent one.
GeneralMy vote of 5 PinmvpPete O'Hanlon4-Feb-11 9:22 
GeneralRe: My vote of 5 Pinmemberleppie4-Feb-11 9:26 
GeneralPlease bear with me till the formatting can be fixed Pinmemberleppie4-Feb-11 8:34 
JokeRe: Please bear with me till the formatting can be fixed Pinmemberfrazzle-me4-Feb-11 8:57 
GeneralRe: Please bear with me till the formatting can be fixed Pinmemberleppie4-Feb-11 9:00 
GeneralRe: Please bear with me till the formatting can be fixed Pinmemberfrazzle-me4-Feb-11 9:15 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.141022.2 | Last Updated 4 Feb 2011
Article Copyright 2011 by leppie
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid