Stripping down a convoluted LINQ expression

This is part 3 of my Blog posts about LINQ testability issues. You know what this is all about when you have read the other two parts here and here.

Before I get down to the nitty gritty let me say thank you to Rainer Schuster who has been faster than me with a conclusive code sample. :-)

First off let me repeat the LINQ expression which we handle here:

public static TContract GetService<TContract>()
         where TContract : class
      {
         string file = Path.Combine(GetProjectPath(EnvironmentMode.UnitTests), "ServiceLocator.xml");
         // Check for configuration file:
         if(!File.Exists(file))
            throw new FileNotFoundException("Service Locator configuration file not found.");
         // Load the configuration.
         // ReSharper disable PossibleNullReferenceException
         mappings =
            (XElement.Load(file).Element("mappings").Elements("mapping")
            .Select(mapping => new KeyValuePair<Type, Type>(
                             Type.GetType(mapping.Attribute("contract").Value),
                             Type.GetType(mapping.Attribute("type").Value)))).ToDictionary(
               kvp => kvp.Key, kvp => kvp.Value);
         // ReSharper restore PossibleNullReferenceException
         // Instantiate the type and return it to the caller.
         return (TContract)Activator.CreateInstance(mappings[typeof(TContract)]);
      }

We dismantle it for better testability and readability. Here is Rainer Schusters suggestion from his comment on the first part (I just fixed some typos):

private static Dictionary<Type, Type> mappings;
 
public static TContract GetService<TContract>()
   where TContract : class
{
   string file = Path.Combine(GetProjectPath(EnvironmentMode.UnitTests), "ServiceLocator.xml");
   // Check for configuration file:
   if(!File.Exists(file))
      throw new FileNotFoundException("Service Locator configuration file not found.");
   // Load the configuration.
   var configMappingElements = XElement.Load(file).Element("mappings").Elements("mapping");
   var map = configMappingElements.Select(elem => ContractTypeMapping(elem));
   mappings = map.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
   // Instantiate the type and return it to the caller.
   return (TContract)Activator.CreateInstance(mappings[typeof(TContract)]);
}
 
private static KeyValuePair<Type, Type> ContractTypeMapping(XElement element)
{
   var contract = Type.GetType(element.Attribute("contract").Value);
   var implementation = Type.GetType(element.Attribute("type").Value);
   return new KeyValuePair<Type, Type>(contract, implementation);
}

We already achieve a great benefit out of this design. All functionality elements do their work separately and if something goes wrong we can see the cause for it immediately. However we could strip this to even more separate methods to improve testability.

DotNetKicks-DE Image
Published Freitag, 30. Oktober 2009 20:45 von Rainer Hilmer

Kommentare

# Lambda Expressions: Warum ich denke daß sie schnell gegen CCD –Prinzipien verstoßen

Donnerstag, 18. Februar 2010 13:16 von Rainer Hilmers Developer-Blog

Oft wird mir etwas unwohl wenn ich eine Lambda expression sehe. Lange Zeit wußte ich nur vage warum überhaupt

Kommentar abgeben

(verpflichtend) 
(verpflichtend) 
(optional)
(verpflichtend)