Posts Tagged ‘.NET’

Reflecting on reflection in .NET

I cringe whenever I spot code that uses System.Reflection. It’s a powerful weapon in our arsenal of .NET programming techniques — and a dangerous one.

In two previous posts, I talked about the misuse of dependency injection and the problems with the service locator pattern. I should include factories among the list of dangerous patterns too.

These patterns get overused in many .NET frameworks and toolkits. Some of that stems from a desire to avoid complex configuration. Some of it comes from the natural envy programmers in stuffy statically typed languages feel regarding their freewheeling counterparts using dynamically typed languages.

(Wikipedia has a good article exploring the differences in type checking in computer language type systems, if you’re curious about the different paradigms. But I digress.)

On reflection

System.Reflection two main uses, as Marc Gravell points out in his answer regarding what problems Reflection solves on StackOverflow:

  1. Investigating type information
  2. Metaprogramming

These two capabilities allow you to shoehorn dynamic or late-binding features into C# applications. In other words, it’s a clever hack.

Want to enable Ruby-style convention over configuration in your C# framework? Use reflection! Want to reach into private or internal methods for unit testing? Use reflection! Want to add some duck typing goodness to your statically typed language? Use reflection!

But on further reflection

The System.Reflection API has some big drawbacks. The performance penalty incurred by reflection is well known. Less well known is that the Reflection API is really difficult to use, especially when inspecting and creating constructor method parameters. So most framework developers skip the hard bits.

This means that most of these frameworks will insist on your using constructors without parameters in your classes. (Sometimes people call parameter-less constructors “default constructors” though it isn’t the same thing.)

But if you can’t use parameters in the constructors of your objects, you’re doing object-oriented programming with one hand tied behind your back.

For example, it’s difficult to achieve object immutability without using a constructor. You’ll also have a hard time enforcing business rules without constructors. And if you’re a fan of dependency injection, you’ll have to implement it via Init() methods or property setters, both of which can cause significant headaches.

So if you work with a framework or API that makes heavy use of reflection, and thus restricts the sort of constructors you use, prepare yourself for significant pain.

The Service Locator pattern is the new global variable

Mark Seeman, author of an upcoming book about dependency injection, writes that Service Locator is an anti-pattern. He shows several code examples illustrating the difficulty of configuring and troubleshooting various implementations of the Service Locator pattern. His observations tally with my thoughts about the awkwardness of service locator implementations.

As I was wrestling with yet another third-party software component that made heavy use of an inversion-of-control (IoC) container, I realized that service locators are the new global variable.

Global variables are a code smell and should be used sparingly.

This means that you should use a service locator only as a last resort, not as the default way of wiring bits of your application together.

And if you’re using an IoC container, make sure that you are using it to inject dependencies through your object constructors, rather than calling its static Resolve() methods from within your classes.

Check out proposed enhancements to .NET core classes

Almost two years ago, I wrote a post expressing my frustration with the way that .NET handles long filenames. Yesterday, the Base Class Library (BCL) team at Microsoft announced that they have launched a BCL CodePlex site to gather feedback on proposed enhancements and extensions to core .NET components.

One of the first four features on preview is a new Long Path wrapper class, which will hopefully make some of the awkward hacks we’ve used in the past obsolete. Hooray!

The code is available for download, and they have documentation and samples as well.

I plan on giving the new Long Path class a thorough test drive.

Creating Dummy Targets for Configuration Objects

The ConfigurationManager class introduced in .NET 2.0 makes it easy to read application settings from an XML file. I especially like the ability to derive a class from ConfigurationSection to hold custom settings for your application. This MSDN tutorial on creating custom configuration sections can help you get started.

I used this to make the configuration files for several of our Infovark add-ins, but ran into a snag with our main API library. In order to interoperate with COM, we had to put out Infovark.Api.dll in the GAC.

This presents a big problem for using *.config files. If your assembly is in the GAC, your configuration file must live in the GAC as well. (By default, configuration files are sidecar files located in the same directory as your *.exe file.) Since the GAC lives in a special place on a Windows machine, it’s difficult to read and write from that location without special permissions. And you can forget about browsing to it using Windows Explorer. This makes it tough for folks to change configuration options, which defeats the whole point of XML-based configuration files.

It’d be nice if we could load the configuration file from an specific spot on the computer. But while the Configuration object has both Save() and SaveAs() methods, there’s no corresponding Load() method. Huh? According to MSDN, the “right” way to point your application at a different configuration file is to create a whole new app domain with the appropriate settings. Um… sure.

How about we just hack up a workaround instead?

Using a dummy target

You can fool the configuration object into loading settings from whatever .config file you want, if you don’t mind a hack or two. The Configuration object exposes an OpenExeConfiguration() method that takes a string. Despite its name, you don’t have to pass it an .exe file. Any file path will do, as long as the path exists.

Since my .dll was in the GAC, I didn’t have a target for the OpenExeConfiguration() to use. I could have pointed it at another .dll — or at a .txt file for that matter — but that wouldn’t be very intuitive. Instead, I created a temporary file without an extension in the location I wanted to save the configuration file. Then I can open a Configuration object using the dummy target. Saving the Configuration object will cause it to write a file named “[configurationTarget].config” to the path I specified. You can see the code I used below.

///
  1.         /// Loads a .NET configuration file using the specified target.
  2.         /// Since configuration files are normally sidecar files, you
  3.         /// normally provide the path to an .exe or .dll file. Unlike
  4.         /// ConfigurationManager.OpenExeConfiguration(), this method
  5.         /// creates a dummy file without an extension to use as its target
  6.         /// if the target file does not always exist.
  7.         ///
  8.         ///
  9. The path and name of the dummy file used as the target.
  10.         /// A Configuration object
  11.         public Configuration LoadConfiguration(string configurationTarget)
  12.         {
  13.             bool useDummyTarget=false;
  14.             try
  15.             {
  16.                 FileInfo fi = new FileInfo(configurationTarget);
  17.                 if (!fi.Exists)
  18.                 {
  19.                     useDummyTarget = true;
  20.                     using (StreamWriter sw = fi.CreateText())
  21.                     {
  22.                         sw.WriteLine("Hi! This file only exists to make the Microsoft .NET framework happy.");
  23.                         sw.WriteLine("It's important because Infovark can't load its configuration file without it.");
  24.                         sw.WriteLine("(Don't ask. It's a long, long story.)");
  25.                         sw.Flush();
  26.                         sw.Close();
  27.                     }
  28.                 }
  29.  
  30.                 return ConfigurationManager.OpenExeConfiguration(configurationTarget);
  31.             }
  32.             catch(Exception e)
  33.             {
  34.                 throw new ConfigurationErrorsException("Unable to load a configuration file using " + configurationTarget + " as a target. See inner exception for details.", e);
  35.             }
  36.             finally
  37.             {
  38.                 // Clean up our dummy file.
  39.                 if (useDummyTarget) File.Delete(configurationTarget);
  40.             }
  41.         }

Once I’ve opened the Configuration object, I don’t need the dummy file any more. I delete it to avoid have weird extension-less files hanging around.

It’s not pretty, but it gets the job done.