Tip of the day: DictionaryAdapter
The is a part of the Castle project but can be used as a standalone assembly.
The dictionary adapter lets you wrap a dictionary with an interface definition and access that dictionary through the interface. This gives the advantage of typed data access on top of a dictionary and don’t forget the intellisense in the IDE.
The example I will use shows the use of a dictionary adapter in order to enable access to configuration data. It contains a class:
////// This class uses configuration. /// Instead of accessing the configuration directly, /// it receives it in the constructor. /// public class DataBaseAccess { private IDataBaseAccessConfig m_config; /// The configuration that /// this class uses to access the database. /// public DataBaseAccess(IDataBaseAccessConfig config) { m_config = config; } public void ConnectToDataBase() { Console.WriteLine("Server Ip: {0}", m_config.ServerIp); Console.WriteLine("DataBase: {0}", m_config.DataBaseName); Console.WriteLine("User: {0}", m_config.UserName); Console.WriteLine("Password: {0}", m_config.Password); Console.ReadLine(); } }
As you can see, this class expects a config object that implements the the IDataBaseAccessConfig interface. This interface is defined as:
////// Defines the data for data base access. /// public interface IDataBaseAccessConfig { string ServerIp { get;} string DataBaseName { get;} string UserName { get;} string Password { get;} }
In the example, the database access data is defined in the appSettings section of the application configuration file. In order to pass it to the DataBaseAccess class, it is being wrapped like this:
// In real world example the factory should be cached. // Create the adapter on top of the configuration dictionary. IDataBaseAccessConfig configAdapter = new DictionaryAdapterFactory(). GetAdapter(configData);
where the configAdapter is passed.
Now what happened here? The DictionaryAdapterFactory emit code in runtime that implements a wrapper class that implemets the IDataBaseAccessConfig interface and this class, when a property is being read, gets the value for the dictionary that is wrapped, in this case, the configData dictionary.
What is it good for?
1) In my opinion, it is nicer to access an interface rather than passing a configuration dictionary to the class which involves querying the data by using string literals.
2) When passing the data through the constructor instead of accessing the ConfigurationManager directly in the code we make our code better by preventing access to singletons, therefore making the code testable and agnostic to the real implementation, may it be the application configuration file, configuration defined in the database or any other implementation.
3) Intellisense…
The example solution is here
November 29th, 2007 at 9:34 am
Hi Reshef,
My name is Tzahi and I’m very interested in your tips.
I have two questions and one comment:
1) what is the performance cost?
2) it seems to me that the adapter can implement simple Interfaces. Specifically, only primitive types of the same type. For example, only strings or only ints, but no combined strings and ints and no objects.
3) as an advocate reader of your tips, wouldn’t aliasing the dictionary also achieve points 1 and 3?
Tzahi
November 29th, 2007 at 11:11 am
Hi Tzahi,
1) Performance: The first time that a type of dictionary adapter (the interface) is requested, the code is being emitted in runtime which takes time though it should be quite fast and then it caches it. Any following call to the factory will return the already created type without performance cost. So to conclude, the performance cost is only at startup.
2) Datatypes: The adapter returns the types as they are - if the dictionary holds a DateTime type, the adapter then should return a DateTime. The adapter doesn’t handle explicit conversion between data types.
In this example, the configuration is stored in an xml file so naturally it will be strings and ints.
3) Aliasing will just let u call the type of the dictionary differently but wouldn’t make it typed and therefore there will be no performance gain.