Castle DictionaryAdapter

June 10, 2008 at 3:02 PMAndre Loker

DictionaryAdapter is a component of the Castle stack which can create an adapter between an interface and a dictionary at runtime. The DictionaryAdapter combines the flexibility of a dictionary with the type safety and convenience provided by a strong API. Here's an example:

   1: // the interface that will be used to access the content of the dictionary
   2: public interface ISimple {
   3:   string Name { get; set; }
   4:   int Age { get; set; }
   5: }
   6:  
   7: //...
   8:  
   9: // the backing store
  10: IDictionary dict = new Hashtable(); 
  11:  
  12: // dynamically create an adapter around dict 
  13: ISimple wrapper = new DictionaryAdapterFactory().GetAdapter<ISimple>(dict);
  14: wrapper.Name = "Andre"; // will be written to dict["Name"];
  15: wrapper.Age = 26;       // will be written to dict["Age"];
  16:  
  17: Assert.AreEqual("Andre", dict["Name"]);
  18: Assert.AreEqual("Andre", wrapper.Name);
  19:  
  20: Assert.AreEqual(26, dict["Age"]);
  21: Assert.AreEqual(26, wrapper.Age);

How to get the DictionaryAdapter

The DictionaryAdapter can be downloaded as part of the Castle project:

How does it work?

Calling DictionaryAdapterFactory.GetAdapter will create a new type on the fly. This type implements the interface that was provided as the type argument (here: ISimple). For each property on the interface a getter and/or setter will be implemented that reads a value from the provided dictionary or writes a value to the dictionary. The key that is used is based on the property name (the default setting is to use the property name as the key, later we will see how we can influence the key being used).

Creating an adapter is rather costly. It requires the creation of a new in-memory assembly containing the dynamic adapter type. However, this performance only exists the first time GetAdapter is called for a specific type. Subsequent requests for the same adapter type will reuse the generated assembly.

More examples and options

DictionaryAdapter has plenty of options to customize how the mapping between the adapter interface and the underlying dictionary happens. In this section I'll give some examples of what DictionaryAdapter is capable of without covering every detail (for a complete reference I'd recommend the Castle source code).

I will provide code examples in the form of an MbUnit test with the following skeleton:

   1: using System.Collections;
   2: using MbUnit.Framework;
   3: using Castle.Components.DictionaryAdapter;
   4:  
   5: [TestFixture]
   6: public class DictionaryAdapterTests {
   7:   private DictionaryAdapterFactory factory;
   8:   private IDictionary dict;
   9:  
  10:   [SetUp]
  11:   public void SetUp() {
  12:     factory = new DictionaryAdapterFactory();
  13:     dict = new Hashtable();
  14:   }
  15: }

The IDictionary instance is used as the backing store for which an adapter will created. The factory handles the dynamic creation of the adapters.

Download the source code of the examples (DictionaryAdapterTests.cs)

Basic example

Ones again, here's the most basic example:

   1: public interface ISimple {
   2:   string Name { get; set; }
   3:   int Age { get; set; }
   4: }
   5:  
   6: [Test]
   7: public void SimpleTest() {
   8:   var wrapper = factory.GetAdapter<ISimple>(dict);
   9:   wrapper.Name = "Andre";
  10:   wrapper.Age = 26;
  11:  
  12:   Assert.AreEqual("Andre", dict["Name"]);
  13:   Assert.AreEqual(26, dict["Age"]);
  14: }

Type prefix

Especially if you want to use multiple adapters on the same dictionary naming collisions can occur if a property with the same name is present in more than one adapter interface. To avoid this problem you can specify key prefixes using attributes. One possible prefix is the (full) name of the interface type:

   1: [DictionaryTypeKeyPrefix]
   2: public interface IWithTypePrefix {
   3:   string Name { get; set; }
   4:   int Age { get; set; }
   5: }
   6:  
   7: [Test]
   8: public void WithTypePrefix() {
   9:   var wrapper = factory.GetAdapter<IWithTypePrefix>(dict);
  10:   wrapper.Name = "Andre";
  11:   wrapper.Age = 26;
  12:  
  13:   Assert.AreEqual("Andre", dict[typeof (IWithTypePrefix).FullName + "#Name"]);
  14:   Assert.AreEqual(26, dict[typeof (IWithTypePrefix).FullName + "#Age"]);
  15: }

Custom prefix

The type prefix can be quite lengthy, so you might prefer setting your own prefix:

   1: [DictionaryKeyPrefix("My")]
   2: public interface IWithCustomPrefix {
   3:   string Name { get; set; }
   4:   int Age { get; set; }
   5: }
   6:  
   7: [Test]
   8: public void WithCustomPrefix() {
   9:   var wrapper = factory.GetAdapter<IWithCustomPrefix>(dict);
  10:   wrapper.Name = "Andre";
  11:   wrapper.Age = 26;
  12:  
  13:   Assert.AreEqual("Andre", dict["MyName"]);
  14:   Assert.AreEqual(26, dict["MyAge"]);
  15: }

Custom keys

You can opt for not using a prefix altogether and define the keys manually:

   1: public interface ICustomKeys {
   2:   [DictionaryKey("Foo")]
   3:   string Name { get; set; }
   4:  
   5:   [DictionaryKey("Bar")]
   6:   int Age { get; set; }
   7: }
   8:  
   9: [Test]
  10: public void WithCustomKey() {
  11:   var wrapper = factory.GetAdapter<ICustomKeys>(dict);
  12:   wrapper.Name = "Andre";
  13:   wrapper.Age = 26;
  14:  
  15:   Assert.AreEqual("Andre", dict["Foo"]);
  16:   Assert.AreEqual(26, dict["Bar"]);
  17: }

Convert property to string

In some scenarios you might need all values in the dictionary to be strings. This can be enforced by using the DictionaryStringValuesAttribute:

   1: public interface IPropertyAsString {
   2:   string Name { get; set; }
   3:  
   4:   [DictionaryStringValues]
   5:   int Age { get; set; }
   6: }
   7:  
   8: [Test]
   9: public void ConvertPropertyToString() {
  10:   var wrapper = factory.GetAdapter<IPropertyAsString>(dict);
  11:   wrapper.Name = "Andre";
  12:   wrapper.Age = 26;
  13:  
  14:   Assert.AreEqual("Andre", dict["Name"]);
  15:   Assert.AreEqual("26", dict["Age"]);
  16: }

This attribute can be applied to the interface itself as well to force all properties to be converted to strings.

Collection as string list

If your property implements IEnumerable you can have it converted to a string containing a list of all values:

   1: public interface IAsStringList {
   2:   [DictionaryStringList]
   3:   int[] Values { get; set; }
   4: }
   5:  
   6: [Test]
   7: public void ConvertPropertyToStringList() {
   8:   var wrapper = factory.GetAdapter<IAsStringList>(dict);
   9:   wrapper.Values = new[] {1, 2, 3, 4, 5};
  10:  
  11:   Assert.AreEqual("1,2,3,4,5", dict["Values"]);
  12: }

Several aspects are configurable, like the separator character.

Adapting complex properties

You are not limited to using "flat" interfaces with only simple types. You can also create an adapter that automatically adapts complex properties:

   1: public interface IWithComponent {
   2:   [DictionaryComponent]
   3:   ISimple Simple { get; }
   4: }
   5:  
   6: [Test]
   7: public void CanUseComponent() {
   8:   var wrapper = factory.GetAdapter<IWithComponent>(dict);
   9:   wrapper.Simple.Name = "Andre";
  10:   wrapper.Simple.Age = 26;
  11:   Assert.AreEqual("Andre", dict["Simple_Name"]);
  12:   Assert.AreEqual(26, dict["Simple_Age"]);
  13: }

As you can see IWithComponent.Simple is automatically populated with an adapter itself.

Conclusion

DictionaryAdapter provides means to access the content of a dictionary in an elegant, type safe way. It is a great tool to get rid of strings and to to make your source code robust and refactorable.

Pro

  • Easy to use
  • Very flexible
  • Type safe access even to IDictionary
  • Great tool to improve robustness of code

Cons

  • One time overhead (creating adapters)
  • Memory overhead (in-memory assemblies created by the factory)

Download source code: DictionaryAdapterTests.cs (2.97 kb)

Posted in: Patterns | Snippets | Tools

Tags: , ,

Comments (7) -

Very useful little trick many thanks for this.

Link to DictionaryAdapterTests.cs is broken... :/
Could you fix it ? Smile because your article is very interesting !!
Thx.

@webflo: thanks for reporting the issue. It seems that some files got lost during the last update of the blog software. I uploaded the files again and should now be able to access the file.

Dave Fletcher
New Zealand Dave Fletcher says:

Is it possible to just get DictionaryAdapter on it's own. I haven't used castle, and I don't fancy downloading and compiling the trunk. This would make a great utility.

Cheers

@Dave: you can grab a precompiled trunk version from the Castle build server

builds.castleproject.org/cruise/index.castle

In the bin directory you'll find Castle.Components.DictionaryAdapter.dll. It can be used standalone, ie. it has no dependency to any other castle lib.

Of course you'll have to stick to the Apache License, but it's very permissive. It shouldn't be a problem for any project.

Do you know where i can find blogengine forum? i want to learn alot about blogengine. Because iam sure blogengine will very popular and this is a chance to sell service like designing theme, modification extention, etc. Thank you

is there any way to get the appsettings values in .vm(view files in castle monorail) directly.
like this <%ConfigurationSettings.AppSettings["key"] %> in asp.net mvc