Freigeben über


Provider Injection With Funcs

Some of the new stuff in .NET 3.5 makes it much easier to implement Provider Injection. If you take a close look at the provider definition, you may discover that when used with Provider Injection, only a single method (Create, or something similarly named) is ever used by the consumer. As such, what we have is essentially an abstraction with only one method (Create). This is true for both ServiceProvider<T> used in my former example, as well as for IServiceProvider.

Allow me to digress for a moment and talk a bit about terminology and how we talk about object-orientation: When I think and talk about object-orientation, I try very hard to stay within the realm of objects. To me, object parameters are passed around as references, not pointers - as far as I'm concerned, a pointer was something I had to deal with when I wrote C++, but it's a low-level detail I don't care to have to deal with anymore. The difference between the words reference and pointer may seem subtle and entirely semantic, but in other cases, the distinction can become much more pronounced.

I've always found it slightly disturbing when people talk about delegates as function pointers. Yes, I admit that the analogy is apparent, but it's not a very object-oriented way to think. To me, a delegate is an anonymous single-method abstraction.

That brings us back to the discussion about service providers, since these are, indeed, single-method abstractions. The implication is that we can model them as delegates. In fact, that has been possible in .NET all along, but until .NET 3.5, the BCL has never offered a good, predefined delegate candidate. In .NET 3.5, however, Func<T> fits the bill perfectly.

If we revisit my previous example, MyClient3 can now be rewritten like so:

 public class MyClient3
 {
     private readonly Func<MyServer> create_;
  
     public MyClient3(Func<MyServer> provider)
     {
         if (provider == null)
         {
             throw new ArgumentNullException("provider");
         }
         this.create_ = provider;
     }
  
     public string GetServerMessage()
     {
         MyServer server = this.create_();
  
         return server.DoStuff("ploeh");
     }
 }

This is pure BCL code with no need for complex containers or funky application blocks.

Unit testing MyClient3 is a breeze as well. Assuming that I have an implementation of MyServer that reverses the message, a unit test is as simple as this:

 [TestMethod]
 public void UseReverseServer()
 {
     MyClient3 mc = new MyClient3(() => new ReverseServer());
  
     string result = mc.GetServerMessage();
  
     Assert.AreEqual<string>("heolp", result);
 }

Notice the lambda expression in the MyClient3 constructor.

Comments

  • Anonymous
    March 27, 2008
    After reading your initial article on Provider Injection it has become my favorite techniq for defining required dependencies. Using Func<T> makes total sence following your "To me, a delegate is an anonymous single-method abstraction" argument. Allthoug something like createMyServer might be more informative then simply create_ (concidering there could be more then one dependency) :)

  • Anonymous
    March 27, 2008
    Hi Olav Thank you for your comment. You are obviously correct when it comes to naming the delegate instance :)