tag:blogger.com,1999:blog-31785481683119143722024-03-05T04:36:10.140-08:00My .NET travelsA blog about my 'travels' in the .NET world and software development in general.Maarten Oosterhoffhttp://www.blogger.com/profile/01939988725191358271noreply@blogger.comBlogger6125tag:blogger.com,1999:blog-3178548168311914372.post-89113005178471012852012-04-28T11:13:00.000-07:002012-04-28T11:24:30.428-07:00Creating my own dependency injection system IIThis post is about extending my own dependency injection system with binding scopes.<br />
<br />
In the <a href="http://dotnettravels.blogspot.com/2012/03/creating-my-own-dependency-injection.html" target="_blank">previous post</a> I showed a very basic DI system. Several things can be added to it, and today I will show how to add binding scopes. What is a binding scope? A binding scope is an indication of when and how the created instances of the DI system should be re-used.<br />
<br />
For example, a <a href="http://en.wikipedia.org/wiki/Singleton_pattern" target="_blank">singleton</a> binding scope. With the singleton binding scope we indicate that once an instance of an object is created for a specific binding rule, no more instances should be created, and that same instance should be returned.<br />
<br />
For now we are going to implement the following binding scopes:<br />
<ul>
<li>Normal – An instance is created every time, is the default scope. </li>
<li><a href="http://en.wikipedia.org/wiki/Singleton_pattern" target="_blank">Singleton</a> – An instance is created once and re-used after. </li>
<li><a href="http://msdn.microsoft.com/en-us/library/system.threadstaticattribute.aspx" target="_blank">Thread</a> – An instance is created per thread, and re-used after in that thread. </li>
<li><a href="http://msdn.microsoft.com/en-us/library/system.web.httpcontext.items(v=vs.100).aspx" target="_blank">WebRequest</a> – An instance is created per web request, and re-used after for that request. </li>
<li><a href="http://msdn.microsoft.com/en-us/library/system.web.httpcontext.session.aspx" target="_blank">WebSession</a> – An instance is created per web session, and re-used after for that session. </li>
<li><a href="http://msdn.microsoft.com/en-us/library/system.web.httpruntime.cache.aspx" target="_blank">WebCache</a> – An instance is created when is not yet available in the caching of the web application.</li>
</ul>
The last three are obviously only applicable in a web application.<br />
<br />
First things first. I updated the code from the previous post:<br />
<ol>
<li>The Factory.GetInstance<TInterface>() method has been renamed to Factory.ResolveInstance<TInterface>(). </li>
<li>Accordingly, the interface IInstanceCreator<TInterface> has been renamed to IInstanceResolver<TInterface>. Also, the Create() method has been renamed to Resolve(). </li>
<li>Accordingly, the class InstanceCreator<TInterface, TClass> has been renamed to InstanceResolver<TInterface, TClass>. And, of course, the method has been renamed as well.</li>
</ol>
Good, that’s done. Onto the binding scopes. To implement the binding scopes we basically need to do two things:<br />
<ol>
<li>Add the ability to indicate the binding scope on a binding rule using the fluent interface. </li>
<li>Update the binding rule or instance resolver so that the binding scope is incorporated.</li>
</ol>
I want to update the fluent interface in the following way.<br />
<div class="csharpcode-wrapper" id="codeSnippetWrapper">
<div class="csharpcode" id="codeSnippet">
<pre class="alt"><span class="lnum" id="lnum1"> 1:</span> Factory.Bind<ICommunicator>().To<WirelessCommunicator>()</pre>
<pre class="alteven"><span class="lnum" id="lnum2"> 2:</span> .WithScope(BindingScope.Singleton);</pre>
<pre class="alt"><span class="lnum" id="lnum3"></span></pre>
</div>
</div>
The first one is simple. First we define a binding scope enumeration.<br />
<div class="csharpcode-wrapper" id="codeSnippetWrapper">
<div class="csharpcode" id="codeSnippet">
<pre class="alt"><span class="lnum" id="lnum1"> 1:</span> <span class="kwrd">namespace</span> MyDI {</pre>
<pre class="alteven"><span class="lnum" id="lnum2"> 2:</span> <span class="kwrd">public</span> <span class="kwrd">enum</span> BindingScope {</pre>
<pre class="alt"><span class="lnum" id="lnum3"> 3:</span> Normal,</pre>
<pre class="alteven"><span class="lnum" id="lnum4"> 4:</span> Singleton,</pre>
<pre class="alt"><span class="lnum" id="lnum5"> 5:</span> Thread,</pre>
<pre class="alteven"><span class="lnum" id="lnum6"> 6:</span> WebRequest,</pre>
<pre class="alt"><span class="lnum" id="lnum7"> 7:</span> WebSession,</pre>
<pre class="alteven"><span class="lnum" id="lnum8"> 8:</span> WebCache</pre>
<pre class="alt"><span class="lnum" id="lnum9"> 9:</span> }</pre>
<pre class="alteven"><span class="lnum" id="lnum10"> 10:</span> }</pre>
</div>
</div>
Now we can add the binding scope to the fluent interface.<br />
<div class="csharpcode-wrapper" id="codeSnippetWrapper">
<div class="csharpcode" id="codeSnippet">
<pre class="alt"><span class="lnum" id="lnum1"> 1:</span> <span class="kwrd">namespace</span> MyDI {</pre>
<pre class="alteven"><span class="lnum" id="lnum2"> 2:</span> <span class="kwrd">public</span> <span class="kwrd">interface</span> IBindingScopeIndicator {</pre>
<pre class="alt"><span class="lnum" id="lnum3"> 3:</span> <span class="kwrd">void</span> WithScope(BindingScope scope);</pre>
<pre class="alteven"><span class="lnum" id="lnum4"> 4:</span> }</pre>
<pre class="alt"><span class="lnum" id="lnum5"> 5:</span> }</pre>
</div>
</div>
<div class="csharpcode-wrapper" id="codeSnippetWrapper">
<div class="csharpcode" id="codeSnippet">
<pre class="alt"><span class="lnum" id="lnum1"> 1:</span> <span class="kwrd">namespace</span> MyDI {</pre>
<pre class="alteven"><span class="lnum" id="lnum2"> 2:</span> <span class="kwrd">public</span> <span class="kwrd">interface</span> IBindingRule { }</pre>
<pre class="alt"><span class="lnum" id="lnum3"> 3:</span> </pre>
<pre class="alteven"><span class="lnum" id="lnum4"> 4:</span> <span class="kwrd">public</span> <span class="kwrd">interface</span> IBindingRule<TInterface> : IBindingRule {</pre>
<pre class="alt"><span class="lnum" id="lnum5"> 5:</span> IBindingScopeIndicator To<TClass>()</pre>
<pre class="alteven"><span class="lnum" id="lnum6"> 6:</span> <span class="kwrd">where</span> TClass : <span class="kwrd">class</span>, TInterface, <span class="kwrd">new</span>();</pre>
<pre class="alt"><span class="lnum" id="lnum7"> 7:</span> }</pre>
<pre class="alteven"><span class="lnum" id="lnum8"> 8:</span> }</pre>
</div>
</div>
<div class="csharpcode-wrapper" id="codeSnippetWrapper">
<div class="csharpcode" id="codeSnippet">
<pre class="alt"><span class="lnum" id="lnum1"> 1:</span> <span class="kwrd">using</span> System;</pre>
<pre class="alteven"><span class="lnum" id="lnum2"> 2:</span> </pre>
<pre class="alt"><span class="lnum" id="lnum3"> 3:</span> <span class="kwrd">namespace</span> MyDI {</pre>
<pre class="alteven"><span class="lnum" id="lnum4"> 4:</span> <span class="kwrd">class</span> BindingRule<TInterface> : IBindingRule<TInterface>, IBindingScopeIndicator {</pre>
<pre class="alt"><span class="lnum" id="lnum5"> 5:</span> <span class="kwrd">private</span> IInstanceResolver<TInterface> _resolver;</pre>
<pre class="alteven"><span class="lnum" id="lnum6"> 6:</span> </pre>
<pre class="alt"><span class="lnum" id="lnum7"> 7:</span> <span class="kwrd">public</span> IBindingScopeIndicator To<TClass>() <span class="kwrd">where</span> TClass : <span class="kwrd">class</span>, TInterface, <span class="kwrd">new</span>() {</pre>
<pre class="alteven"><span class="lnum" id="lnum8"> 8:</span> _resolver = <span class="kwrd">new</span> InstanceResolver<TInterface, TClass>();</pre>
<pre class="alt"><span class="lnum" id="lnum9"> 9:</span> <span class="kwrd">return</span> <span class="kwrd">this</span>;</pre>
<pre class="alteven"><span class="lnum" id="lnum10"> 10:</span> }</pre>
<pre class="alt"><span class="lnum" id="lnum11"> 11:</span> </pre>
<pre class="alteven"><span class="lnum" id="lnum12"> 12:</span> <span class="kwrd">public</span> TInterface Create() {</pre>
<pre class="alt"><span class="lnum" id="lnum13"> 13:</span> <span class="kwrd">if</span> (_resolver != <span class="kwrd">null</span>) {</pre>
<pre class="alteven"><span class="lnum" id="lnum14"> 14:</span> <span class="kwrd">return</span> _resolver.Resolve();</pre>
<pre class="alt"><span class="lnum" id="lnum15"> 15:</span> }</pre>
<pre class="alteven"><span class="lnum" id="lnum16"> 16:</span> <span class="kwrd">throw</span> <span class="kwrd">new</span> InvalidOperationException();</pre>
<pre class="alt"><span class="lnum" id="lnum17"> 17:</span> }</pre>
<pre class="alteven"><span class="lnum" id="lnum18"> 18:</span> </pre>
<pre class="alt"><span class="lnum" id="lnum19"> 19:</span> <span class="kwrd">public</span> <span class="kwrd">void</span> WithScope(BindingScope scope) {</pre>
<pre class="alteven"><span class="lnum" id="lnum20"> 20:</span> <span class="rem">// TODO</span></pre>
<pre class="alt"><span class="lnum" id="lnum21"> 21:</span> <span class="kwrd">throw</span> <span class="kwrd">new</span> NotImplementedException();</pre>
<pre class="alteven"><span class="lnum" id="lnum22"> 22:</span> }</pre>
<pre class="alt"><span class="lnum" id="lnum23"> 23:</span> }</pre>
<pre class="alteven"><span class="lnum" id="lnum24"> 24:</span> }</pre>
</div>
</div>
So what did we do? We added an interface with which to indicate the binding scope. This interface has to be returned after the IBindingRule<TInterface>.To<TClass>() method, so this method was updated to return an IBindingScopeIndicator interface.<br />
<br />
Last, the binding rule class was updated to reflect the changes in the binding rule interface, and it now also implements the IBindingScopeIndicator interface. The implementation of the method IBindingScopeIndicator.WithScope(BindingScope) will be done later.<br />
<br />
We can now update the unittests, and add a failing unittest for the singleton scope.<br />
<div class="csharpcode-wrapper" id="codeSnippetWrapper">
<div class="csharpcode" id="codeSnippet">
<pre class="alt"><span class="lnum" id="lnum1"> 1:</span> <span class="kwrd">using</span> Microsoft.VisualStudio.TestTools.UnitTesting;</pre>
<pre class="alteven"><span class="lnum" id="lnum2"> 2:</span> <span class="kwrd">using</span> MyDI;</pre>
<pre class="alt"><span class="lnum" id="lnum3"> 3:</span> </pre>
<pre class="alteven"><span class="lnum" id="lnum4"> 4:</span> <span class="kwrd">namespace</span> MyDI_Tests {</pre>
<pre class="alt"><span class="lnum" id="lnum5"> 5:</span> [TestClass]</pre>
<pre class="alteven"><span class="lnum" id="lnum6"> 6:</span> <span class="kwrd">public</span> <span class="kwrd">class</span> FactoryTests {</pre>
<pre class="alt"><span class="lnum" id="lnum7"> 7:</span> [TestMethod]</pre>
<pre class="alteven"><span class="lnum" id="lnum8"> 8:</span> <span class="kwrd">public</span> <span class="kwrd">void</span> Test_normal_type_correct() {</pre>
<pre class="alt"><span class="lnum" id="lnum9"> 9:</span> Factory.Clear();</pre>
<pre class="alteven"><span class="lnum" id="lnum10"> 10:</span> Factory.Bind<ICommunicator>().To<WirelessCommunicator>();</pre>
<pre class="alt"><span class="lnum" id="lnum11"> 11:</span> var test = Factory.ResolveInstance<ICommunicator>();</pre>
<pre class="alteven"><span class="lnum" id="lnum12"> 12:</span> Assert.IsNotNull(test);</pre>
<pre class="alt"><span class="lnum" id="lnum13"> 13:</span> Assert.AreEqual(<span class="kwrd">typeof</span>(WirelessCommunicator), test.GetType());</pre>
<pre class="alteven"><span class="lnum" id="lnum14"> 14:</span> }</pre>
<pre class="alt"><span class="lnum" id="lnum15"> 15:</span> </pre>
<pre class="alteven"><span class="lnum" id="lnum16"> 16:</span> [TestMethod]</pre>
<pre class="alt"><span class="lnum" id="lnum17"> 17:</span> <span class="kwrd">public</span> <span class="kwrd">void</span> Test_normal_scope_check() {</pre>
<pre class="alteven"><span class="lnum" id="lnum18"> 18:</span> Factory.Clear();</pre>
<pre class="alt"><span class="lnum" id="lnum19"> 19:</span> Factory.Bind<ICommunicator>().To<WirelessCommunicator>();</pre>
<pre class="alteven"><span class="lnum" id="lnum20"> 20:</span> var test1 = Factory.ResolveInstance<ICommunicator>();</pre>
<pre class="alt"><span class="lnum" id="lnum21"> 21:</span> var test2 = Factory.ResolveInstance<ICommunicator>();</pre>
<pre class="alteven"><span class="lnum" id="lnum22"> 22:</span> Assert.IsNotNull(test1);</pre>
<pre class="alt"><span class="lnum" id="lnum23"> 23:</span> Assert.AreEqual(<span class="kwrd">typeof</span>(WirelessCommunicator), test1.GetType());</pre>
<pre class="alteven"><span class="lnum" id="lnum24"> 24:</span> Assert.IsNotNull(test2);</pre>
<pre class="alt"><span class="lnum" id="lnum25"> 25:</span> Assert.AreEqual(<span class="kwrd">typeof</span>(WirelessCommunicator), test2.GetType());</pre>
<pre class="alteven"><span class="lnum" id="lnum26"> 26:</span> Assert.AreNotEqual(test1, test2);</pre>
<pre class="alt"><span class="lnum" id="lnum27"> 27:</span> }</pre>
<pre class="alteven"><span class="lnum" id="lnum28"> 28:</span> </pre>
<pre class="alt"><span class="lnum" id="lnum29"> 29:</span> [TestMethod]</pre>
<pre class="alteven"><span class="lnum" id="lnum30"> 30:</span> <span class="kwrd">public</span> <span class="kwrd">void</span> Test_singleton_scope_check() {</pre>
<pre class="alt"><span class="lnum" id="lnum31"> 31:</span> Factory.Clear();</pre>
<pre class="alteven"><span class="lnum" id="lnum32"> 32:</span> Factory.Bind<ICommunicator>().To<WirelessCommunicator>().WithScope(BindingScope.Singleton);</pre>
<pre class="alt"><span class="lnum" id="lnum33"> 33:</span> var test1 = Factory.ResolveInstance<ICommunicator>();</pre>
<pre class="alteven"><span class="lnum" id="lnum34"> 34:</span> var test2 = Factory.ResolveInstance<ICommunicator>();</pre>
<pre class="alt"><span class="lnum" id="lnum35"> 35:</span> Assert.IsNotNull(test1);</pre>
<pre class="alteven"><span class="lnum" id="lnum36"> 36:</span> Assert.AreEqual(<span class="kwrd">typeof</span>(WirelessCommunicator), test1.GetType());</pre>
<pre class="alt"><span class="lnum" id="lnum37"> 37:</span> Assert.IsNotNull(test2);</pre>
<pre class="alteven"><span class="lnum" id="lnum38"> 38:</span> Assert.AreEqual(<span class="kwrd">typeof</span>(WirelessCommunicator), test2.GetType());</pre>
<pre class="alt"><span class="lnum" id="lnum39"> 39:</span> Assert.AreEqual(test1, test2);</pre>
<pre class="alteven"><span class="lnum" id="lnum40"> 40:</span> }</pre>
<pre class="alt"><span class="lnum" id="lnum41"> 41:</span> }</pre>
<pre class="alteven"><span class="lnum" id="lnum42"> 42:</span> }</pre>
</div>
</div>
The first two unittests pass, the last one fails.<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhnCyIEdjNqvcc8cQ2vULizC7vMDXyjeC5oU4f9FSWeI9j4r5QybjbJuUaNMmVHeM3R3PCWOS_KQMyFfLALRoAH5QIXl1sa-Tmd_OsuGITf1tBFm5yQ2M7P5J74d1Mc0B7hNAIkiQQJjwO7/s1600-h/image%25255B3%25255D.png"><img alt="image" border="0" height="202" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEieeJYITWt5kU9irSZ6g0JUQ9hWh5e4owp0o9EC2gfubINmvDnLPLgvIi-kAEGrXp-7QKJGMGkxbQL9wHoHBNNjuc5jsoOhinxu12dqMk6PxmGGLOEG_uOQS6Y7Poe0JdphP3OWnhOIkjrw/?imgmax=800" style="background-image: none; border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="image" width="673" /></a><br />
<br />
We now have to update the InstanceResolver class to do something with the given binding scope.<br />
<br />
To prevent our InstanceResolver class from cluttering up, I am going to define an interface called IScopeHandler<TClass>. The purpose of this interface is to, obviously, handle the scope of a binding rule. Therefore we will have implementations for every binding scope, NormaleScopeHandler, SingletonScopeHandler, ThreadScopeHandler, and so forth. In this post I will only show the class for the first three binding scopes, the rest will be in the code that can be downloaded at the bottom of the post.<br />
<br />
Lets define the scope handler interface, and create the scope handler classes.<br />
<div class="csharpcode-wrapper" id="codeSnippetWrapper">
<div class="csharpcode" id="codeSnippet">
<pre class="alt"><span class="lnum" id="lnum1"> 1:</span> <span class="kwrd">namespace</span> MyDI {</pre>
<pre class="alteven"><span class="lnum" id="lnum2"> 2:</span> <span class="kwrd">public</span> <span class="kwrd">interface</span> IScopeHandler<TClass> <span class="kwrd">where</span> TClass : <span class="kwrd">class</span>, <span class="kwrd">new</span>() {</pre>
<pre class="alt"><span class="lnum" id="lnum3"> 3:</span> TClass GetInstance();</pre>
<pre class="alteven"><span class="lnum" id="lnum4"> 4:</span> }</pre>
<pre class="alt"><span class="lnum" id="lnum5"> 5:</span> }</pre>
</div>
</div>
<div class="csharpcode-wrapper" id="codeSnippetWrapper">
<div class="csharpcode" id="codeSnippet">
<pre class="alt"><span class="lnum" id="lnum1"> 1:</span> <span class="kwrd">namespace</span> MyDI.ScopeHandlers {</pre>
<pre class="alteven"><span class="lnum" id="lnum2"> 2:</span> <span class="kwrd">public</span> <span class="kwrd">class</span> NormalScopeHandler<TClass> : IScopeHandler<TClass> <span class="kwrd">where</span> TClass : <span class="kwrd">class</span>, <span class="kwrd">new</span>() {</pre>
<pre class="alt"><span class="lnum" id="lnum3"> 3:</span> <span class="kwrd">public</span> TClass GetInstance() {</pre>
<pre class="alteven"><span class="lnum" id="lnum4"> 4:</span> <span class="kwrd">return</span> <span class="kwrd">new</span> TClass(); </pre>
<pre class="alt"><span class="lnum" id="lnum5"> 5:</span> }</pre>
<pre class="alteven"><span class="lnum" id="lnum6"> 6:</span> }</pre>
<pre class="alt"><span class="lnum" id="lnum7"> 7:</span> }</pre>
</div>
</div>
<div class="csharpcode-wrapper" id="codeSnippetWrapper">
<div class="csharpcode" id="codeSnippet">
<pre class="alt"><span class="lnum" id="lnum1"> 1:</span> <span class="kwrd">using</span> System;</pre>
<pre class="alteven"><span class="lnum" id="lnum2"> 2:</span> </pre>
<pre class="alt"><span class="lnum" id="lnum3"> 3:</span> <span class="kwrd">namespace</span> MyDI.ScopeHandlers {</pre>
<pre class="alteven"><span class="lnum" id="lnum4"> 4:</span> <span class="kwrd">public</span> <span class="kwrd">class</span> SingletonScopeHandler<TClass> : IScopeHandler<TClass> <span class="kwrd">where</span> TClass : <span class="kwrd">class</span>, <span class="kwrd">new</span>() {</pre>
<pre class="alt"><span class="lnum" id="lnum5"> 5:</span> <span class="kwrd">private</span> Lazy<TClass> _value = <span class="kwrd">new</span> Lazy<TClass>(() => <span class="kwrd">new</span> TClass(), <span class="kwrd">true</span>);</pre>
<pre class="alteven"><span class="lnum" id="lnum6"> 6:</span> </pre>
<pre class="alt"><span class="lnum" id="lnum7"> 7:</span> <span class="kwrd">public</span> TClass GetInstance() {</pre>
<pre class="alteven"><span class="lnum" id="lnum8"> 8:</span> <span class="kwrd">return</span> _value.Value;</pre>
<pre class="alt"><span class="lnum" id="lnum9"> 9:</span> }</pre>
<pre class="alteven"><span class="lnum" id="lnum10"> 10:</span> }</pre>
<pre class="alt"><span class="lnum" id="lnum11"> 11:</span> }</pre>
</div>
</div>
<div class="csharpcode-wrapper" id="codeSnippetWrapper">
<div class="csharpcode" id="codeSnippet">
<pre class="alt"><span class="lnum" id="lnum1"> 1:</span> <span class="kwrd">using</span> System;</pre>
<pre class="alteven"><span class="lnum" id="lnum2"> 2:</span> </pre>
<pre class="alt"><span class="lnum" id="lnum3"> 3:</span> <span class="kwrd">namespace</span> MyDI.ScopeHandlers {</pre>
<pre class="alteven"><span class="lnum" id="lnum4"> 4:</span> <span class="kwrd">public</span> <span class="kwrd">class</span> ThreadScopeHandler<TClass> : IScopeHandler<TClass> <span class="kwrd">where</span> TClass : <span class="kwrd">class</span>, <span class="kwrd">new</span>() {</pre>
<pre class="alt"><span class="lnum" id="lnum5"> 5:</span> [ThreadStatic]</pre>
<pre class="alteven"><span class="lnum" id="lnum6"> 6:</span> <span class="kwrd">private</span> <span class="kwrd">static</span> TClass _value = <span class="kwrd">null</span>;</pre>
<pre class="alt"><span class="lnum" id="lnum7"> 7:</span> </pre>
<pre class="alteven"><span class="lnum" id="lnum8"> 8:</span> <span class="kwrd">public</span> TClass GetInstance() {</pre>
<pre class="alt"><span class="lnum" id="lnum9"> 9:</span> <span class="kwrd">if</span> (_value == <span class="kwrd">null</span>)</pre>
<pre class="alteven"><span class="lnum" id="lnum10"> 10:</span> _value = <span class="kwrd">new</span> TClass();</pre>
<pre class="alt"><span class="lnum" id="lnum11"> 11:</span> <span class="kwrd">return</span> _value;</pre>
<pre class="alteven"><span class="lnum" id="lnum12"> 12:</span> }</pre>
<pre class="alt"><span class="lnum" id="lnum13"> 13:</span> }</pre>
<pre class="alteven"><span class="lnum" id="lnum14"> 14:</span> }</pre>
</div>
</div>
So what is exactly happening here?<br />
<br />
<u>Interface IScopeHandler<TClass></u> This interface defines a scope handler. A scope handler has only one method, which is to get an instance of the class-type.<br />
<br />
<u>Class NormalScopeHandler<TClass></u> This class creates an object every time the method GetInstance() is called.<br />
<br />
<u>Class SingletonScopeHandler<TClass></u> This class creates an object once, and uses it every time the method GetInstance() is called.<br />
<br />
<u>Class ThreadScopeHandler<TClass></u> This class has a field with a ThreadStatic attribute, and that field is used to hold an object per thread, and that object is used every time the method GetInstance() is called. Logically this binding scope is very similar to the singleton binding scope. The implementation is a bit different though.<br />
<br />
Now that we have scope handlers, we need a handy place to get scope handler instances. For this, a scope handler factory is created.<br />
<div class="csharpcode-wrapper" id="codeSnippetWrapper">
<div class="csharpcode" id="codeSnippet">
<pre class="alt"><span class="lnum" id="lnum1"> 1:</span> <span class="kwrd">using</span> System;</pre>
<pre class="alteven"><span class="lnum" id="lnum2"> 2:</span> <span class="kwrd">using</span> MyDI.ScopeHandlers;</pre>
<pre class="alt"><span class="lnum" id="lnum3"> 3:</span> </pre>
<pre class="alteven"><span class="lnum" id="lnum4"> 4:</span> <span class="kwrd">namespace</span> MyDI {</pre>
<pre class="alt"><span class="lnum" id="lnum5"> 5:</span> <span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">class</span> ScopeHandlerFactory {</pre>
<pre class="alteven"><span class="lnum" id="lnum6"> 6:</span> <span class="kwrd">private</span> <span class="kwrd">const</span> <span class="kwrd">string</span> SCOPEHANDLERNOTREGISTEREDEXCEPTIONMESSAGE = <span class="str">"The specified scope handler was not registered."</span>;</pre>
<pre class="alt"><span class="lnum" id="lnum7"> 7:</span> </pre>
<pre class="alteven"><span class="lnum" id="lnum8"> 8:</span> <span class="kwrd">public</span> <span class="kwrd">static</span> IScopeHandler<TClass> GetScopeHandler<TClass>(BindingScope scope) <span class="kwrd">where</span> TClass : <span class="kwrd">class</span>, <span class="kwrd">new</span>() {</pre>
<pre class="alt"><span class="lnum" id="lnum9"> 9:</span> <span class="kwrd">switch</span> (scope) {</pre>
<pre class="alteven"><span class="lnum" id="lnum10"> 10:</span> <span class="kwrd">case</span> BindingScope.Normal:</pre>
<pre class="alt"><span class="lnum" id="lnum11"> 11:</span> <span class="kwrd">return</span> <span class="kwrd">new</span> NormalScopeHandler<TClass>();</pre>
<pre class="alteven"><span class="lnum" id="lnum12"> 12:</span> <span class="kwrd">case</span> BindingScope.Singleton:</pre>
<pre class="alt"><span class="lnum" id="lnum13"> 13:</span> <span class="kwrd">return</span> <span class="kwrd">new</span> SingletonScopeHandler<TClass>();</pre>
<pre class="alteven"><span class="lnum" id="lnum14"> 14:</span> <span class="kwrd">case</span> BindingScope.Thread:</pre>
<pre class="alt"><span class="lnum" id="lnum15"> 15:</span> <span class="kwrd">return</span> <span class="kwrd">new</span> ThreadScopeHandler<TClass>();</pre>
<pre class="alteven"><span class="lnum" id="lnum16"> 16:</span> <span class="kwrd">case</span> BindingScope.WebRequest:</pre>
<pre class="alt"><span class="lnum" id="lnum17"> 17:</span> <span class="kwrd">return</span> <span class="kwrd">new</span> WebRequestScopeHandler<TClass>();</pre>
<pre class="alteven"><span class="lnum" id="lnum18"> 18:</span> <span class="kwrd">case</span> BindingScope.WebSession:</pre>
<pre class="alt"><span class="lnum" id="lnum19"> 19:</span> <span class="kwrd">return</span> <span class="kwrd">new</span> WebSessionScopeHandler<TClass>();</pre>
<pre class="alteven"><span class="lnum" id="lnum20"> 20:</span> <span class="kwrd">case</span> BindingScope.WebCache:</pre>
<pre class="alt"><span class="lnum" id="lnum21"> 21:</span> <span class="kwrd">return</span> <span class="kwrd">new</span> WebCacheScopeHandler<TClass>();</pre>
<pre class="alteven"><span class="lnum" id="lnum22"> 22:</span> }</pre>
<pre class="alt"><span class="lnum" id="lnum23"> 23:</span> <span class="kwrd">throw</span> <span class="kwrd">new</span> InvalidOperationException(SCOPEHANDLERNOTREGISTEREDEXCEPTIONMESSAGE);</pre>
<pre class="alteven"><span class="lnum" id="lnum24"> 24:</span> }</pre>
<pre class="alt"><span class="lnum" id="lnum25"> 25:</span> }</pre>
<pre class="alteven"><span class="lnum" id="lnum26"> 26:</span> }</pre>
</div>
</div>
Now we’re getting somewhere. We have scope handlers, and a class to get them. Now we can update the InstanceResolver class. And we can do that very easily.<br />
<div class="csharpcode-wrapper" id="codeSnippetWrapper">
<div class="csharpcode" id="codeSnippet">
<pre class="alt"><span class="lnum" id="lnum1"> 1:</span> <span class="kwrd">namespace</span> MyDI {</pre>
<pre class="alteven"><span class="lnum" id="lnum2"> 2:</span> <span class="kwrd">class</span> InstanceResolver<TInterface, TClass> : IInstanceResolver<TInterface> <span class="kwrd">where</span> TClass : <span class="kwrd">class</span>, TInterface, <span class="kwrd">new</span>() {</pre>
<pre class="alt"><span class="lnum" id="lnum3"> 3:</span> <span class="kwrd">private</span> IScopeHandler<TClass> _scopeHandler = ScopeHandlerFactory.GetScopeHandler<TClass>(BindingScope.Normal);</pre>
<pre class="alteven"><span class="lnum" id="lnum4"> 4:</span> </pre>
<pre class="alt"><span class="lnum" id="lnum5"> 5:</span> <span class="kwrd">public</span> TInterface Resolve() {</pre>
<pre class="alteven"><span class="lnum" id="lnum6"> 6:</span> <span class="kwrd">return</span> _scopeHandler.GetInstance();</pre>
<pre class="alt"><span class="lnum" id="lnum7"> 7:</span> }</pre>
<pre class="alteven"><span class="lnum" id="lnum8"> 8:</span> </pre>
<pre class="alt"><span class="lnum" id="lnum9"> 9:</span> <span class="kwrd">public</span> <span class="kwrd">void</span> SetScope(BindingScope scope) {</pre>
<pre class="alteven"><span class="lnum" id="lnum10"> 10:</span> _scopeHandler = ScopeHandlerFactory.GetScopeHandler<TClass>(scope);</pre>
<pre class="alt"><span class="lnum" id="lnum11"> 11:</span> }</pre>
<pre class="alteven"><span class="lnum" id="lnum12"> 12:</span> }</pre>
<pre class="alt"><span class="lnum" id="lnum13"> 13:</span> }</pre>
</div>
</div>
A default normal scope handler is retrieved when the instance resolver is instanced. When necessary, it is replaced with another scope handler based on the given binding scope.<br />
<br />
Lastly, we can update the BindingRule class to implement the method SetScope().<br />
<div class="csharpcode-wrapper" id="codeSnippetWrapper">
<div class="csharpcode" id="codeSnippet">
<pre class="alt"><span class="lnum" id="lnum1"> 1:</span> <span class="kwrd">using</span> System;</pre>
<pre class="alteven"><span class="lnum" id="lnum2"> 2:</span> </pre>
<pre class="alt"><span class="lnum" id="lnum3"> 3:</span> <span class="kwrd">namespace</span> MyDI {</pre>
<pre class="alteven"><span class="lnum" id="lnum4"> 4:</span> <span class="kwrd">class</span> BindingRule<TInterface> : IBindingRule<TInterface>, IBindingScopeIndicator {</pre>
<pre class="alt"><span class="lnum" id="lnum5"> 5:</span> <span class="kwrd">private</span> IInstanceResolver<TInterface> _resolver;</pre>
<pre class="alteven"><span class="lnum" id="lnum6"> 6:</span> </pre>
<pre class="alt"><span class="lnum" id="lnum7"> 7:</span> <span class="kwrd">public</span> IBindingScopeIndicator To<TClass>() <span class="kwrd">where</span> TClass : <span class="kwrd">class</span>, TInterface, <span class="kwrd">new</span>() {</pre>
<pre class="alteven"><span class="lnum" id="lnum8"> 8:</span> _resolver = <span class="kwrd">new</span> InstanceResolver<TInterface, TClass>();</pre>
<pre class="alt"><span class="lnum" id="lnum9"> 9:</span> <span class="kwrd">return</span> <span class="kwrd">this</span>;</pre>
<pre class="alteven"><span class="lnum" id="lnum10"> 10:</span> }</pre>
<pre class="alt"><span class="lnum" id="lnum11"> 11:</span> </pre>
<pre class="alteven"><span class="lnum" id="lnum12"> 12:</span> <span class="kwrd">public</span> TInterface Create() {</pre>
<pre class="alt"><span class="lnum" id="lnum13"> 13:</span> <span class="kwrd">if</span> (_resolver != <span class="kwrd">null</span>) {</pre>
<pre class="alteven"><span class="lnum" id="lnum14"> 14:</span> <span class="kwrd">return</span> _resolver.Resolve();</pre>
<pre class="alt"><span class="lnum" id="lnum15"> 15:</span> }</pre>
<pre class="alteven"><span class="lnum" id="lnum16"> 16:</span> <span class="kwrd">throw</span> <span class="kwrd">new</span> InvalidOperationException();</pre>
<pre class="alt"><span class="lnum" id="lnum17"> 17:</span> }</pre>
<pre class="alteven"><span class="lnum" id="lnum18"> 18:</span> </pre>
<pre class="alt"><span class="lnum" id="lnum19"> 19:</span> <span class="kwrd">public</span> <span class="kwrd">void</span> WithScope(BindingScope scope) {</pre>
<pre class="alteven"><span class="lnum" id="lnum20"> 20:</span> _resolver.SetScope(scope);</pre>
<pre class="alt"><span class="lnum" id="lnum21"> 21:</span> }</pre>
<pre class="alteven"><span class="lnum" id="lnum22"> 22:</span> }</pre>
<pre class="alt"><span class="lnum" id="lnum23"> 23:</span> }</pre>
</div>
</div>
Now all unittests are passing again. Excellent!<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPmHsBP1ioecTghQsR4HmmClueMooJFFTbDzag6EMVdojvyJY6J7cZDGU5gwhxneZsq2yIhY1s-ZpMNo9MYYkwZ0eo7oFn9XUMAiPwKjpBmBVzPfKFWw5nU2JSdfNU-DRSJOPgJSoVYe_A/s1600-h/image4.png"><img alt="image" border="0" height="254" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0gDS8TnB-vZHTWTXYPHs8cVx6fd00aRl_0R9hDwygl9ym7OAuUNmARI7NZ3o-boGjTIfQZsJBy4CK2bvyqjTyD9thyphenhyphencxrsr3q2FvhSYMPkjDhmFTFWDLacHAm0H2td2vVaC1uJtRPDorP/?imgmax=800" style="background-image: none; border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="image" width="663" /></a><br />
<br />
To add the other binding scopes, all we have to do is write the specific scope handler class, and add it to the factory.<br />
<br />
The code can be downloaded <a href="https://sites.google.com/site/dotnettravels/MyDI_2012_04_19.zip" target="_blank">here</a>.<br />
<br />
I’m not sure what will be next, maybe constructor-injection, but <a href="http://stackoverflow.com/questions/2420193/dependency-injection-constructor-madness">not everyone thinks this is a good thing</a>.Maarten Oosterhoffhttp://www.blogger.com/profile/01939988725191358271noreply@blogger.com0tag:blogger.com,1999:blog-3178548168311914372.post-15404122920224936552012-03-13T07:00:00.001-07:002012-03-13T07:03:35.627-07:00Creating my own dependency injection system<p>This post is about creating my own dependency injection system.</p><p>Dependency injection allows us to inject dependencies at run-time instead of compile-time. I’m going to start with the simple version, which I’ll describe using the following requirements:</p><ol><li>I want to define a binding between an interface and a class using generics. Obviously the class must implement the interface.<br />
<ul><li>This means that all dependencies must be known at compile-time. So for now I’m not going to include any run-time loaded types based on string values, or any other similar methods.</li>
</ul><li>I want to use fluent interfaces to define the binding.<br />
<li>I want to be able to resolve an instance of an object by specifying the interface type.<br />
</ol><p>Going from the list above I could come up with the following way to define a binding and to get an instance of an class:</p><div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"><div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum1"> 1:</span> <span style="color: #0000ff">namespace</span> MyDI_Tests {</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum2"> 2:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">class</span> Test {</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum3"> 3:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">void</span> DoTest() {</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum4"> 4:</span> Factory.Bind<ITestObject>().To<TestObject>();</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum5"> 5:</span> var test = Factory.GetInstance<ITestObject>();</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum6"> 6:</span> <span style="color: #008000">// test should be of type TestObject</span></pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum7"> 7:</span> }</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum8"> 8:</span> }</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum9"> 9:</span> }</pre><!--CRLF--></div></div><p>In the text below, I will reference to the ITestObject type as the <em>interface-type</em> and the TestObject type as the <em>class-type.</em></p><p>All right, lets make it happen. First we need a Factory class.</p><div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"><div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum1"> 1:</span> <span style="color: #0000ff">namespace</span> MyDI {</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum2"> 2:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">class</span> Factory {</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum3"> 3:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> IBindingRule<TInterface> Bind<TInterface>() {</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum4"> 4:</span> <span style="color: #008000">// TODO</span></pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum5"> 5:</span> <span style="color: #0000ff">throw</span> <span style="color: #0000ff">new</span> NotImplementedException();</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum6"> 6:</span> }</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum7"> 7:</span> </pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum8"> 8:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> TInterface GetInstance<TInterface>() {</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum9"> 9:</span> <span style="color: #008000">// TODO</span></pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum10"> 10:</span> <span style="color: #0000ff">throw</span> <span style="color: #0000ff">new</span> NotImplementedException();</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum11"> 11:</span> }</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum12"> 12:</span> }</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum13"> 13:</span> }</pre><!--CRLF--></div></div><p>We are also in need of an interface to define a binding rule. We’ll worry about the implementation later.</p><div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"><div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum1"> 1:</span> <span style="color: #0000ff">namespace</span> MyDI {</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum2"> 2:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">interface</span> IBindingRule<TInterface> {</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum3"> 3:</span> <span style="color: #0000ff">void</span> To<TClass>() <span style="color: #0000ff">where</span> TClass : <span style="color: #0000ff">class</span>, TInterface, <span style="color: #0000ff">new</span>();</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum4"> 4:</span> }</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum5"> 5:</span> }</pre><!--CRLF--></div></div><p>And presto, now we can define binding rules in the factory. Let’s create a unittest. We need a dummy interface and class, and a unittest class.</p><div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"><div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum1"> 1:</span> <span style="color: #0000ff">namespace</span> MyDI_Tests {</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum2"> 2:</span> <span style="color: #0000ff">interface</span> ICommunicator {</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum3"> 3:</span> <span style="color: #0000ff">void</span> SendCommand(<span style="color: #0000ff">string</span> command);</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum4"> 4:</span> }</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum5"> 5:</span> </pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum6"> 6:</span> <span style="color: #0000ff">class</span> WirelessCommunicator : ICommunicator {</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum7"> 7:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> SendCommand(<span style="color: #0000ff">string</span> command) {</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum8"> 8:</span> <span style="color: #0000ff">throw</span> <span style="color: #0000ff">new</span> System.NotImplementedException();</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum9"> 9:</span> }</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum10"> 10:</span> }</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum11"> 11:</span> }</pre><!--CRLF--></div></div><div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"><div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum1"> 1:</span> <span style="color: #0000ff">namespace</span> MyDI_Tests {</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum2"> 2:</span> [TestClass]</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum3"> 3:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> FactoryTests {</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum4"> 4:</span> [TestMethod]</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum5"> 5:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> TestMethod1() {</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum6"> 6:</span> Factory.Bind<ICommunicator>().To<WirelessCommunicator>();</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum7"> 7:</span> var test = Factory.GetInstance<ICommunicator>();</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum8"> 8:</span> Assert.IsNotNull(test);</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum9"> 9:</span> Assert.AreEqual(<span style="color: #0000ff">typeof</span>(WirelessCommunicator), test.GetType());</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum10"> 10:</span> }</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum11"> 11:</span> }</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum12"> 12:</span> }</pre><!--CRLF--></div></div><p>Now we can run our unittest, and obviously it fails.</p><p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiqcAz91UOC0N3fCaM2x3zBTSQSXYWfjUhCcsiAmfvKsj0-JqVlxJtqArZc9JnV2S7XMaln9JBdb5xZW6FijprodX2QB5l5nnraKpiO2uwzln-k6ZXmRSm_Fa0OH9w1RvZKaIZJLtxjDoru/s1600-h/image%25255B16%25255D.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjCgsPbhvNKYkJAzWTVV0O4A6FKcGV2hHBTfETST3ALa0vTmPDvF0qS7kNoD0yl7C-fWxC-TubzPR1u7m6qEqBGh7dkAcS1krzX6WWbU5_AUHr1nz7xl8R-SMAbKkWehhn73MhP-s9pRrYb/?imgmax=800" width="667" height="200"></a></p><p>We need to create a binding rule class, and finish the factory class. To do that, we are also going to need another class, a class which will actually create an instance of an object. The reason for this is the following: When the Factory.Bind<TInterface>() method is called, an instance of the binding rule class is created. But the IBindingRule<TInterface>.To<TClass>() method specifies to which class-type the binding-rule should use. Therefore the binding rule cannot hold the class-type, and this is where the ‘instance creator’ comes into play. The instance creator class knows the interface-type, and the class-type, and therefore can return an object of the class-type.</p><p>I was struggling with the instance creator class at first, but once I figured out that the interface <em>doesn’t</em> know the class-type, and the class <em>does</em> know the class-type, things started to work out.</p><p>To reference the non-generic binding rules from the Factory a non-generic binding rule interface is necessary; the generic binding rule interface of course inherits this interface as well.</p><p>Lets create the binding rule class, the instance creator interface and class, and finish the factory class.</p><div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"><div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum1"> 1:</span> <span style="color: #0000ff">namespace</span> MyDI {</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum2"> 2:</span> <span style="color: #0000ff">interface</span> IInstanceCreator<TInterface> {</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum3"> 3:</span> TInterface Create();</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum4"> 4:</span> }</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum5"> 5:</span> }</pre><!--CRLF--></div></div><div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"><div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum1"> 1:</span> <span style="color: #0000ff">namespace</span> MyDI {</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum2"> 2:</span> <span style="color: #0000ff">class</span> InstanceCreator<TInterface, TClass> : IInstanceCreator<TInterface></pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum3"> 3:</span> <span style="color: #0000ff">where</span> TClass : <span style="color: #0000ff">class</span>, TInterface, <span style="color: #0000ff">new</span>() {</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum4"> 4:</span> <span style="color: #0000ff">public</span> TInterface Create() {</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum5"> 5:</span> <span style="color: #0000ff">return</span> <span style="color: #0000ff">new</span> TClass();</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum6"> 6:</span> }</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum7"> 7:</span> }</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum8"> 8:</span> }</pre><!--CRLF--></div></div><div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"><div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum1"> 1:</span> <span style="color: #0000ff">namespace</span> MyDI {</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum2"> 2:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">interface</span> IBindingRule { }</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum3"> 3:</span> </pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum4"> 4:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">interface</span> IBindingRule<TInterface> : IBindingRule {</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum5"> 5:</span> <span style="color: #0000ff">void</span> To<TClass>() <span style="color: #0000ff">where</span> TClass : <span style="color: #0000ff">class</span>, TInterface, <span style="color: #0000ff">new</span>();</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum6"> 6:</span> }</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum7"> 7:</span> }</pre><!--CRLF--></div></div><div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"><div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum1"> 1:</span> <span style="color: #0000ff">namespace</span> MyDI {</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum2"> 2:</span> <span style="color: #0000ff">class</span> BindingRule<TInterface> : IBindingRule<TInterface> {</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum3"> 3:</span> <span style="color: #0000ff">private</span> IInstanceCreator<TInterface> _creator;</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum4"> 4:</span> </pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum5"> 5:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> To<TClass>() <span style="color: #0000ff">where</span> TClass : <span style="color: #0000ff">class</span>, TInterface, <span style="color: #0000ff">new</span>() {</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum6"> 6:</span> _creator = <span style="color: #0000ff">new</span> InstanceCreator<TInterface, TClass>();</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum7"> 7:</span> }</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum8"> 8:</span> </pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum9"> 9:</span> <span style="color: #0000ff">public</span> TInterface Create() {</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum10"> 10:</span> <span style="color: #0000ff">if</span> (_creator != <span style="color: #0000ff">null</span>) {</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum11"> 11:</span> <span style="color: #0000ff">return</span> _creator.Create();</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum12"> 12:</span> }</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum13"> 13:</span> <span style="color: #0000ff">throw</span> <span style="color: #0000ff">new</span> InvalidOperationException();</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum14"> 14:</span> }</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum15"> 15:</span> }</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum16"> 16:</span> }</pre><!--CRLF--></div></div><div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"><div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum1"> 1:</span> <span style="color: #0000ff">namespace</span> MyDI {</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum2"> 2:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">class</span> Factory {</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum3"> 3:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> IBindingRule<TInterface> Bind<TInterface>() {</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum4"> 4:</span> <span style="color: #0000ff">throw</span> <span style="color: #0000ff">new</span> KeyNotFoundException();</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum5"> 5:</span> <span style="color: #0000ff">if</span> (!_bindingRules.ContainsKey(<span style="color: #0000ff">typeof</span>(TInterface))) {</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum6"> 6:</span> var bindingRule = <span style="color: #0000ff">new</span> BindingRule<TInterface>();</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum7"> 7:</span> _bindingRules.Add(<span style="color: #0000ff">typeof</span>(TInterface), bindingRule);</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum8"> 8:</span> <span style="color: #0000ff">return</span> bindingRule;</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum9"> 9:</span> }</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum10"> 10:</span> <span style="color: #0000ff">throw</span> <span style="color: #0000ff">new</span> InvalidOperationException();</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum11"> 11:</span> }</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum12"> 12:</span> </pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum13"> 13:</span> <span style="color: #0000ff">private</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">readonly</span> Dictionary<Type, IBindingRule> _bindingRules = <span style="color: #0000ff">new</span> Dictionary<Type, IBindingRule>();</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum14"> 14:</span> </pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum15"> 15:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> TInterface GetInstance<TInterface>() {</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum16"> 16:</span> <span style="color: #0000ff">if</span> (_bindingRules.ContainsKey(<span style="color: #0000ff">typeof</span>(TInterface)) && _bindingRules[<span style="color: #0000ff">typeof</span>(TInterface)] <span style="color: #0000ff">is</span> BindingRule<TInterface>) {</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum17"> 17:</span> <span style="color: #0000ff">return</span> ((BindingRule<TInterface>)_bindingRules[<span style="color: #0000ff">typeof</span>(TInterface)]).Create();</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum18"> 18:</span> }</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum19"> 19:</span> <span style="color: #0000ff">throw</span> <span style="color: #0000ff">new</span> InvalidOperationException();</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum20"> 20:</span> }</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum21"> 21:</span> }</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum22"> 22:</span> }</pre><!--CRLF--></div></div><p>So what is exactly happening here?</p><p><u>Interface IInstanceCreator<TInterface></u> This interface defines an instance creator. Generics-wise it only knows the interface-type, since the binding rule must hold a reference to the instance creator. It has a single method, the Create() method, which is meant to return an instance of an object which implements the interface-type.</p><p><u>Class InstanceCreator<TInterface, TClass></u> This class implements the IInstanceCreator<TInterface> interface, and therefore has a Create() method. This method can simple create a new object of the class-type using the parameterless constructor.</p><p><u>Interface IBindingRule</u> This interface defines a non-generic binding rule. This is necessary for the factory to reference a collection of binding rules. Of course it could be a list of objects as well, but using this interface it is somewhat strongly typed.</p><p><u>Interface IBindingRule<TInterface></u> This interface defines a generic binding rule. This interface exposes a single method to define the binding, specifying the class-type using generics.</p><p><u>Class BindingRule<TInterface></u> This class implements the IBindingRule<TInterface> interface. It is actually very simple. When the To<TClass> method is called, an instance of the InstanceCreator class is created. When the Create method is called, the instance creator is used to create an instance of the class-type.</p><p><u>Class Factory</u> This class provides public access to the binding rules by exposing two static methods. One is the Bind<TInterface> method which can be used to create a binding rule. The binding rule is stored in a private dictionary. The other method is the GetInstance<TInterface> method in which a binding rule is retrieved from the dictionary, and the Create-method is used to get an instance of the object.</p><p>Now we have a unittest that passes. Excellent! </p><p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj5gEiCdtIWxv-b0W7W0n_yK5g8LoBlefovZquv_d8Na1501WUUygWzCHW2RlyQ8qKxwbzwRn0Ab1LyF2mJTmGLYhM-IsggdgPS_hd1xcE2Er1ZrMxQ4PDUa_n1AZsH4rlmi4pC0cF8nHim/s1600-h/image%25255B12%25255D.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiAf_a4J2DZ-xdfC901psX4vBxl5rcPmuF2iNmJ9ngnNZYdxB7JmXtcsNES4JUchBw3EUFlz0CI2eBarn7wSHQYJccmdsk3Pd4tW-mXbFzjBwsgC0aV2OOWC6E7aD7ds8rYCo1sqiKUrCCX/?imgmax=800" width="664" height="199"></a></p><p>Using the factory we can define a binding rule in one assembly, and get an instance of a class that normally wouldn’t be accessible (without using reflection or some other method). The following diagram shows what I mean.</p><p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiScNtvipaEZmcViBD8zwTq0O0A3Yh7OAP-ZITB3zGt7t8z66bYwp0rnEkmy2CTcJvCcyuaclZnqx0cMjey2gliDKkb7qY2XQPWu2YfV7enbV2A8QtEgASBkD-c4hV07hhySJRAFy571dkL/s1600-h/image9%25255B1%25255D.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtpXRxoGLBYacYjCAQ6Faz90pKTqlDQ7b-nvpeq5S32_l65N0CX-bSvH-TLGFXKlpIdhCCS2mytCRnatveLtGeCRcrFshT-g-g-Jt1cqh1ghyphenhyphenzfvxGkMe9swfi1ZvOhoG5uF7dhRX8HeLO/?imgmax=800" width="437" height="246"></a></p><p>In the core assembly an interface is defined, and in that same assembly we want to use it. But the implementation is done in the implementing assembly which we can´t reference, since that assembly references the core assembly. This is possible using the factory.</p><p>Please note that the code shown above is not yet thread-safe.</p><p>In the next post I will introduce the concept of the binding scope. With the binding scope we can specify if and how previously created objects are re-used. For example: a singleton-scope.</p><p>The code can be downloaded <a href="https://sites.google.com/site/dotnettravels/MyDI_2012_03_13.zip">here</a>.</p>Maarten Oosterhoffhttp://www.blogger.com/profile/01939988725191358271noreply@blogger.com2tag:blogger.com,1999:blog-3178548168311914372.post-77237203361473900802011-02-24T07:40:00.001-08:002012-03-04T22:58:28.792-08:00A generic object creator using expression trees (part 3)This blog series contains the following posts:<br />
<a href="http://dotnettravels.blogspot.com/2010/12/generic-object-creator-using-expression.html">1. Create an instance of an object using the constructor with no parameters</a><br />
<a href="http://dotnettravels.blogspot.com/2010/12/generic-object-creator-using-expression_14.html">2. Create an instance of an object using the constructor with parameters</a><br />
<a href="http://dotnettravels.blogspot.com/2011/02/generic-object-creator-using-expression.html">3. Caching the compiled expression tree</a><br />
<br />
In the previous posts in this series I showed how to create an instance of an object, using expression trees, both without parameters, and with parameters. Now, unless the compiled expression tree is saved somewhere it's not going to be very quick, since the compilation of the expression tree into a lambda is the most expensive action.<br />
<br />
For this purpose, I'll create a simple class LambdaCacher which will keep a dictionary containing the lambdas with their keys. The key for a lambda is the return type in combination with the types of the constructor arguments. To create a key is simple: just concatenate all Type.FullName values, and I'm using a pipe (|) to separate the full names.<br />
<br />
If you look back at the previous post there is a method called CreateLambda in the ObjectCreator class, which creates the lambda. This will be the perfect place to use the new LambdaCacher class.<br />
<br />
The LambdaCacher class will be static, and will have two static methods from an external point of view, each with two overloads. A LoadLambda method to retrieve an earlier compiled lambda, and a SaveLambda method to store a compiled lambda.<br />
<br />
Internally the LambdaCacher class will have a dictionary of some key, and the lambdas as value. Since the lambdas are specified using generics, the dictionary will have a key of type string, and a value of type object. Some things are added to enforce thread safety.<br />
<pre class="brush:csharp">using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Playground {
internal static class LambdaCacher {
private static readonly object _lock = new object();
private static readonly Dictionary<string, object> _lambdas = new Dictionary<string, object>();
private static string GenerateKey(Type type, Type[] types) {
string key = type.FullName + "|";
if (types != null) {
key += string.Join("|", types.Select(t => t.FullName).ToArray());
}
return key;
}
public static TFunc LoadLambda<TFunc>(Type type) where TFunc : class {
return LoadLambda<TFunc>(type, null);
}
public static TFunc LoadLambda<TFunc>(Type type, Type[] types) where TFunc : class {
lock (_lock) {
string key = GenerateKey(type, types);
if (_lambdas.ContainsKey(key)) {
return (TFunc)_lambdas[key];
}
return null;
}
}
public static void SaveLambda<TFunc>(TFunc func, Type type) {
SaveLambda<TFunc>(func, type, null);
}
public static void SaveLambda<TFunc>(TFunc func, Type type, Type[] types) {
lock (_lock) {
string key = GenerateKey(type, types);
if (!_lambdas.ContainsKey(key)) {
_lambdas.Add(key, func);
} else {
throw new ArgumentException("A lambda is already saved for this type (and parameter types is given).");
}
}
}
}
}
</pre>And now we have to use the new CreateLambda method in the ObjectCreate class.<br />
<pre class="brush:csharp">...
private static TFunc CreateLambda<TBase, TFunc>(Type type, ParameterExpression[] parameters, Type[] types)
where TBase : class
where TFunc : class {
var constructor = type.GetConstructor(types);
if (constructor == null)
throw new Exception(string.Format("Type '{0}' has no constructor with the specified parameters.", type.FullName));
TFunc lambda = LambdaCacher.LoadLambda<TFunc>(type, types);
if (lambda != null)
return lambda;
Expression expression = Expression.New(constructor, parameters);
if (type != typeof(TBase)) {
expression = Expression.Convert(expression, typeof(TBase));
}
expression = Expression.Lambda(expression, parameters);
var creatorExpression = expression as Expression<TFunc>;
lambda = creatorExpression.Compile();
LambdaCacher.SaveLambda<TFunc>(lambda, type, types);
return lambda;
}
...
</pre>Of course, the question is now if it actually makes any difference. A test is in order.<br />
<br />
The first test will create 1 object.<br />
Running without the lambda cacher: 0.0103251 seconds<br />
Running with the lambda cacher: 0.0272546 seconds<br />
<br />
The first test will create 10 object.<br />
Running without the lambda cacher: 0.0429771 seconds<br />
Running with the lambda cacher: 0.0177748 seconds<br />
<br />
The second test will create 100.000 objects.<br />
Running without the lambda cacher: 25.31 seconds<br />
Running with the lambda cacher: 0.0693901 seconds<br />
<br />
In the first two tests I noticed that the times were not always identical. I suspect that the times necessary are too small to make a real difference, and some startup costs might be different each time. But the third test does show how effective the caching the of lambdas is.<br />
<br />
In the next post I'll do some performance testing comparing Reflection and the usage of expression trees.<br />
<br />
The code as it is now can be downloaded <a href="https://sites.google.com/site/dotnettravels/ObjectCreator_20110224.zip">here</a>.Maarten Oosterhoffhttp://www.blogger.com/profile/01939988725191358271noreply@blogger.com0tag:blogger.com,1999:blog-3178548168311914372.post-81986668494527157552010-12-14T23:11:00.000-08:002011-02-24T07:53:03.845-08:00A generic object creator using expression trees (part 2)This blog series contains the following posts:<br />
<a href="http://dotnettravels.blogspot.com/2010/12/generic-object-creator-using-expression.html">1. Create an instance of an object using the constructor with no parameters</a><br />
<a href="http://dotnettravels.blogspot.com/2010/12/generic-object-creator-using-expression_14.html">2. Create an instance of an object using the constructor with parameters</a><br />
<a href="http://dotnettravels.blogspot.com/2011/02/generic-object-creator-using-expression.html">3. Caching the compiled expression tree</a><br />
<br />
In the <a href="http://dotnettravels.blogspot.com/2010/12/generic-object-creator-using-expression.html">previous post</a> in this series I showed how to create an instance of an object, using expression trees, using the constructor with no parameters. In this post I will show how to do it using a constructor with parameters.<br />
<br />
This was a little more difficult. My biggest problem was getting the expression parameters right. Getting the expression itself right was not that difficult, it is almost the same as the previous one.<br />
<br />
We now have to use <a href="http://msdn.microsoft.com/en-us/library/bb351483.aspx">another overload</a> of the <a href="http://msdn.microsoft.com/en-us/library/system.linq.expressions.expression.new.aspx">new expression</a>. It uses a <a href="http://msdn.microsoft.com/en-us/library/system.reflection.constructorinfo.aspx">ConstructorInfo</a> object to specify which constructor overload you want to use, and you have to supply the correct parameters.<br />
<br />
First step is to retrieve a ConstructorInfo object. This can be retrieved from the type, using the <a href="http://msdn.microsoft.com/en-us/library/system.type.getconstructor.aspx">GetContructor</a> method.<br />
<pre class="brush:csharp">using System;
using System.Reflection;
namespace Playground {
public static partial class ObjectCreator {
public static TClass CreateObject<TClass, TParam1>(Func<TParam1> param1Provider) {
var constructorInfo = typeof(TClass).GetConstructor(new Type[] { typeof(TParam1) });
// TODO: Finish this
}
}
}
</pre>Once we have the ConstructorInfo object, we can use that to create a new expression.<br />
<pre class="brush:csharp">using System;
using System.Reflection;
using System.Linq.Expressions;
namespace Playground {
public static partial class ObjectCreator {
public static TClass CreateObject<TClass, TParam1>(Func<TParam1> param1Provider) {
var constructorInfo = typeof(TClass).GetConstructor(new Type[] { typeof(TParam1) });
var parameter = Expression.Parameter(typeof(TParam1));
var newExpression = Expression.New(constructorInfo, parameter);
// TODO: Finish this
}
}
}
</pre>And now we can create a lambda expression using the new expression.<br />
<pre class="brush:csharp">using System;
using System.Reflection;
using System.Linq.Expressions;
namespace Playground {
public static partial class ObjectCreator {
public static TClass CreateObject<TClass, TParam1>(Func<TParam1> param1Provider) {
var constructorInfo = typeof(TClass).GetConstructor(new Type[] { typeof(TParam1) });
var parameter = Expression.Parameter(typeof(TParam1));
var newExpression = Expression.New(constructorInfo, parameter);
var creatorExpression = Expression.Lambda(newExpression, parameter) as Expression<Func<TParam1, TClass>>;
// TODO: Finish this
}
}
}
</pre>Now we only have to compile the expression to get the lambda itself, and execute it.<br />
<pre class="brush:csharp">using System;
using System.Reflection;
using System.Linq.Expressions;
namespace Playground {
public static partial class ObjectCreator {
public static TClass CreateObject<TClass, TParam1>(Func<TParam1> param1Provider) {
var constructorInfo = typeof(TClass).GetConstructor(new Type[] { typeof(TParam1) });
var parameter = Expression.Parameter(typeof(TParam1));
var newExpression = Expression.New(constructorInfo, parameter);
var creatorExpression = Expression.Lambda(newExpression, parameter) as Expression<Func<TParam1, TClass>>;
var creator = creatorExpression.Compile();
if (creator != null) {
return creator(param1Provider());
}
throw new Exception("Cannot create instance.");
}
}
}
</pre>This only gives us a method to use a constructor with a single parameter, but the methods for multiple parameter are essentially copies of the method above. With some refactoring I come to the following code.<br />
<pre class="brush:csharp">using System;
using System.Reflection;
using System.Linq;
using System.Linq.Expressions;
namespace Playground {
public static partial class ObjectCreator {
public static TClass CreateObject<TClass, TParam1>(Func<TParam1> param1Provider) {
var parameters = CreateArray<Type, ParameterExpression>(t => Expression.Parameter(t), typeof(TParam1));
var types = CreateArray<Type, Type>(t => t, typeof(TParam1));
var creator = CreateLambda<TClass, Func<TParam1, TClass>>(parameters, types);
if (creator != null) {
return creator(param1Provider());
}
throw new Exception("Cannot create instance.");
}
public static TClass CreateObject<TClass, TParam1, TParam2>(Func<TParam1> param1Provider, Func<TParam2> param2Provider) {
var parameters = CreateArray<Type, ParameterExpression>(t => Expression.Parameter(t), typeof(TParam1), typeof(TParam2));
var types = CreateArray<Type, Type>(t => t, typeof(TParam1), typeof(TParam2));
var creator = CreateLambda<TClass, Func<TParam1, TParam2, TClass>>(parameters, types);
if (creator != null) {
return creator(param1Provider(), param2Provider());
}
throw new Exception("Cannot create instance.");
}
public static TClass CreateObject<TClass, TParam1, TParam2, TParam3>(Func<TParam1> param1Provider, Func<TParam2> param2Provider, Func<TParam3> param3Provider) {
var parameters = CreateArray<Type, ParameterExpression>(t => Expression.Parameter(t), typeof(TParam1), typeof(TParam2), typeof(TParam3));
var types = CreateArray<Type, Type>(t => t, typeof(TParam1), typeof(TParam2), typeof(TParam3));
var creator = CreateLambda<TClass, Func<TParam1, TParam2, TParam3, TClass>>(parameters, types);
if (creator != null) {
return creator(param1Provider(), param2Provider(), param3Provider());
}
throw new Exception("Cannot create instance.");
}
public static TClass CreateObject<TClass, TParam1, TParam2, TParam3, TParam4>(Func<TParam1> param1Provider, Func<TParam2> param2Provider, Func<TParam3> param3Provider, Func<TParam4> param4Provider) {
var parameters = CreateArray<Type, ParameterExpression>(t => Expression.Parameter(t), typeof(TParam1), typeof(TParam2), typeof(TParam3), typeof(TParam4));
var types = CreateArray<Type, Type>(t => t, typeof(TParam1), typeof(TParam2), typeof(TParam3), typeof(TParam4));
var creator = CreateLambda<TClass, Func<TParam1, TParam2, TParam3, TParam4, TClass>>(parameters, types);
if (creator != null) {
return creator(param1Provider(), param2Provider(), param3Provider(), param4Provider());
}
throw new Exception("Cannot create instance.");
}
private static TFunc CreateLambda<TClass, TFunc>(ParameterExpression[] parameters, Type[] types) {
var constructor = typeof(TClass).GetConstructor(types);
if (constructor == null)
throw new Exception(string.Format("Type '{0}' has no constructor with the specified parameters.", typeof(TClass).FullName));
var newExpression = Expression.New(constructor, parameters);
var creatorExpression = Expression.Lambda(newExpression, parameters) as Expression<TFunc>;
return creatorExpression.Compile();
}
private static TResult[] CreateArray<TSource, TResult>(Func<TSource, TResult> transformer, params TSource[] source) {
return source.Select(transformer).ToArray();
}
}
}
</pre>Now we can create an instance of an object using constructor parameters.<br />
<pre class="brush:csharp">namespace Playground.Program {
class MyTestClass {
public int I { get; set; }
public string J { get; set; }
public MyTestClass() { }
public MyTestClass(int i) { I = i; }
public MyTestClass(int i, string j) : this(i) { J = j; }
}
class Program {
static void Main(string[] args) {
// Use the generic version with parameters
MyTestClass o1 = ObjectCreator.CreateObject<MyTestClass, int>(() => 10);
MyTestClass o2 = ObjectCreator.CreateObject<MyTestClass, int, string>(() => 10, () => "Test");
List<int> baseList = new List<int>(new int[] { 1, 2, 3, 4, 5 });
List<int> list = ObjectCreator.CreateObject<List<int>, IEnumerable<int>>(() => baseList);
}
}
}
</pre>Once again, this is just the generic version, but it is no problem to convert it to parameter versions as I've shown in the previous post in this series. But I'll include that when I upload the complete code, which I'll do in one of the following posts. In the next post I'll be saving the generated lambda's so they can be re-used at a later stage.Maarten Oosterhoffhttp://www.blogger.com/profile/01939988725191358271noreply@blogger.com0tag:blogger.com,1999:blog-3178548168311914372.post-55672195350868000142010-12-07T07:26:00.000-08:002011-02-24T07:45:02.342-08:00A generic object creator using expression trees (part 1)This blog series contains the following posts:<br />
<a href="http://dotnettravels.blogspot.com/2010/12/generic-object-creator-using-expression.html">1. Create an instance of an object using the constructor with no parameters</a><br />
<a href="http://dotnettravels.blogspot.com/2010/12/generic-object-creator-using-expression_14.html">2. Create an instance of an object using the constructor with parameters</a><br />
<a href="http://dotnettravels.blogspot.com/2011/02/generic-object-creator-using-expression.html">3. Caching the compiled expression tree</a><br />
<br />
One of the things I've bumped into in the past years is that using reflection to create an instance of an object is a solution that works, but somehow I do not like it. In the time of .NET 2.0 it was the only option, but with .NET 3.0 another option was made available: expression trees. I like it, but unfortunately haven't used it much. Therefore I went looking for information about expression trees. The <a href="http://msdn.microsoft.com/en-us/library/bb397951.aspx">msdn site</a> provided me with plenty information.<br />
<br />
Expression trees are described on msdn as follows: <i>Expression trees represent code in a tree-like data structure, where each node is an expression, for example, a method call or a binary operation such as x < y.</i><br />
<br />
Today I will show how to create an instance of an object using the constructor with no parameters, using expression trees.<br />
<br />
Creating an object without any constructor parameters turned out not to be very difficult.<br />
<pre class="brush:csharp">using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
namespace Playground {
public static class ObjectCreator {
public static TClass CreateObject<TClass>() where TClass : new() {
Expression<Func<TClass>> creatorExpression =
Expression.Lambda(
Expression.New(typeof(TClass)),
null
) as Expression<Func<TClass>>;
Func<TClass> creator = creatorExpression.Compile();
if (creator != null) {
return creator();
}
throw new Exception("Cannot create instance.");
}
}
}
</pre>What is going on here? We have a generic method which creates an expression tree, compiles the expression tree into a lambda, and executes the lambda, and returns the result of the executed lambda.<br />
<br />
The expression tree is the difficult part of the method. It is a <a href="http://msdn.microsoft.com/en-us/library/bb336566.aspx">lambda expression</a> since we want it to become a lambda after compilation, and the lambda contains a <a href="http://msdn.microsoft.com/en-us/library/system.linq.expressions.expression.new.aspx">new expression</a>. The new expression has multiple overloads, and <a href="http://msdn.microsoft.com/en-us/library/bb352804.aspx">one of them</a> takes a parameter of type Type. This is the overload for no constructor parameters.<br />
<br />
Since the new expression only validates the given type at run-time, I've added the new() constraint on the TClass generic parameter, so the check for a parameterless constructor is done at compile-time.<br />
<br />
This doesn't work if for some reason, at compile-time, we cannot reference the assembly with the type we need. Say you load an assembly to load a specific type, and you want to create an instance of that type. Than you cannot use the generic version. This means we need another method which can use a parameter of type Type, and create an instance of that.<br />
<br />
After some fiddling around I came to the following methods.<br />
<pre class="brush:csharp">using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
namespace Playground {
public static partial class ObjectCreator {
public static TClass CreateObject<TClass>() where TClass : new() {
return CreateObject<TClass>(typeof(TClass));
}
public static object CreateObject(Type type) {
return CreateObject<object>(type);
}
public static TBase CreateObject<TBase>(Type type) {
Expression expression = Expression.New(type);
if (type != typeof(TBase)) {
expression = Expression.Convert(expression, typeof(TBase));
}
expression = Expression.Lambda(expression, null);
Expression<Func<TBase>> creatorExpression = expression as Expression<Func<TBase>>;
Func<TBase> creator = creatorExpression.Compile();
if (creator != null) {
return creator();
}
throw new Exception("Cannot create instance.");
}
}
}
</pre>Now we have three methods.<br />
<ul><li>One if you can specify the type at compile time</li>
<li>One if you cannot specify the type at compile time</li>
<li>One if you cannot specify the type at compile-time, but you <u>can</u> specify a base-class of the type</li>
</ul><br />
It was necessary to alter the expression a bit, since the expression created by the lambda expression is of the type that is given, and cannot be cast to type Expression<Func<object>> for example. To work around this, a <a href="http://msdn.microsoft.com/en-us/library/bb292051.aspx">convert expression</a> is inserted if the type to instance is different from the type to return.<br />
<br />
Now we can create instances as follows:<br />
<pre class="brush:csharp">namespace Playground.Program {
class MyTestClass { }
class MyDerivedTestClass : MyTestClass { }
class Program {
static void Main(string[] args) {
// Use the generic version
MyTestClass c = ObjectCreator.CreateObject<MyTestClass>();
// Use the parameter version
object o = ObjectCreator.CreateObject(typeof(MyTestClass));
// Use the baseclass+parameter version
MyTestClass c2 = ObjectCreator.CreateObject<MyTestClass>(typeof(MyDerivedTestClass));
}
}
}
</pre>Notes:<br />
<ul><li>The first method of the three now calls another overload. Since a new() constraint is added to the generic type TClass, we could simply do 'return new TClass()'.<br />
</li>
<li>In the next post(s) I will show how to create an instance of an object with constructor parameters. Also I will add caching of the expression trees, since in the above code the expression trees are generated everytime when the method is called, and that is not necessary.<br />
</li>
</ul>Maarten Oosterhoffhttp://www.blogger.com/profile/01939988725191358271noreply@blogger.com3tag:blogger.com,1999:blog-3178548168311914372.post-40177029944590482372010-11-24T03:52:00.000-08:002010-11-24T04:29:52.869-08:00First post: adding code to a postAs a first post, I'd like to add something I ran into when trying to make this blog work: adding code to a post. Of course I would like for it to look nice.<br />
<br />
After some searching I found <a href="http://the-simple-programmer.blogspot.com/2010/02/bloggercom-code-syntax-highlighting-or.html">this</a> post by Iain which explains exactly that.<br />
<br />
The short of it:<br />
1) Add the following in the head section of your blog.<br />
<pre class="brush: html"><link href='http://alexgorbatchev.com/pub/sh/current/styles/shCore.css' rel='stylesheet' type='text/css'/>
<link href='http://alexgorbatchev.com/pub/sh/current/styles/shThemeDefault.css' rel='stylesheet' type='text/css'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shCore.js' type='text/javascript'></script>
<!-- add brushes here -->
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushJScript.js' type='text/javascript'></script>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushBash.js' type='text/javascript'></script>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushSql.js' type='text/javascript'></script>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushXml.js' type='text/javascript'></script>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCpp.js' type='text/javascript'></script>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCSharp.js' type='text/javascript'></script>
<script type='text/javascript'>
SyntaxHighlighter.config.bloggerMode = true;
SyntaxHighlighter.all();
</script>
</pre>2) Add your <a href="http://www.string-functions.com/htmlencode.aspx">html-encoded</a> text in the following html tags:<br />
<pre class="brush:html"><pre class="brush:csharp">
...your code..
</pre>
</pre>Here is an example of the result:<br />
<pre class="brush:csharp">using System;
namespace Demo {
class Program {
static void Main(string[] args) {
Console.WriteLine("Hello world!");
}
}
}
</pre>It works for all kinds of languages, and also for C#. Just what I needed :-)<br />
<br />
Kudos to <a href="http://alexgorbatchev.com/SyntaxHighlighter/about.html">Alex Gorbatchev</a> for creating this wonderful piece of javascript, and to <a href="http://the-simple-programmer.blogspot.com/2010/02/bloggercom-code-syntax-highlighting-or.html">Iain</a> for letting me find it.Maarten Oosterhoffhttp://www.blogger.com/profile/01939988725191358271noreply@blogger.com0