<file_sep>﻿// Tech-F Framework
// (C) Copyright 2014 <NAME><<EMAIL>>
//
// All rights reserved.This program and the accompanying materials
// are made available under the terms of the GNU Lesser General Public License
// (LGPL) version 2.1 which accompanies this distribution, and is available at
// http://www.gnu.org/licenses/lgpl-2.1.html
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the GNU
// Lesser General Public License for more details.
//
// Contributors:
//     <NAME><<EMAIL>>
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TechF.Configuration
{
    //ncrunch: no coverage start
    public class ClassFactoryPropertyElement : ConfigurationElement
    {
        [ConfigurationProperty("name", IsRequired = true)]
        public string Name
        {
            get
            {
                return Convert.ToString(this["name"]);
            }
        }
        [ConfigurationProperty("value", IsRequired = true)]
        public string Value
        {
            get
            {
                return Convert.ToString(this["value"]);
            }
        }
    }
    [ConfigurationCollection(typeof(ClassFactoryPropertyElement), AddItemName = "Property", CollectionType = ConfigurationElementCollectionType.BasicMap)]
    public class ClassFactoryPropertyCollection : ConfigurationElementCollection, IEnumerable<ClassFactoryPropertyElement>
    {
        public ClassFactoryPropertyCollection()
        {
            AddElementName = "Property";
        }

        protected override ConfigurationElement CreateNewElement()
        {
            return new ClassFactoryPropertyElement();
        }

        protected override object GetElementKey(ConfigurationElement element)
        {
            return ((ClassFactoryPropertyElement)element).Name;
        }

        IEnumerator<ClassFactoryPropertyElement> IEnumerable<ClassFactoryPropertyElement>.GetEnumerator()
        {
            foreach (var i in base.BaseGetAllKeys())
            {
                var o = (ClassFactoryPropertyElement)BaseGet(i);
                if (o != null)
                    yield return o;
            }
        }
        public ClassFactoryPropertyElement this[int index]
        {
            get
            {
                return (ClassFactoryPropertyElement)BaseGet(index);
            }
        }
        public new ClassFactoryPropertyElement this[string index]
        {
            get
            {
                return (ClassFactoryPropertyElement)BaseGet(index);
            }
        }
    }

    public class ClassFactoryElement : ConfigurationElement
    {
        [ConfigurationProperty("type", IsRequired = true)]
        public string Type
        {
            get
            {
                return Convert.ToString(this["type"]);
            }
        }
        [ConfigurationProperty("factoryType", IsRequired = true)]
        public string FactoryType
        {
            get
            {
                return Convert.ToString(this["factoryType"]);
            }
        }
        [ConfigurationProperty("persistPerContext", DefaultValue = false, IsRequired = false)]
        public bool PersistsPerContext
        {
            get
            {
                return Convert.ToBoolean(this["persistPerContext"]);
            }
        }
        [ConfigurationProperty("FactoryProperties", IsRequired = false)]
        public ClassFactoryPropertyCollection FactoryProperties
        {
            get
            {
                return (ClassFactoryPropertyCollection)this["FactoryProperties"];
            }
        }
    }
    [ConfigurationCollection(typeof(ClassFactoryElement), AddItemName = "Factory", CollectionType = ConfigurationElementCollectionType.BasicMap)]
    public class ClassFactoryCollection : ConfigurationElementCollection, IEnumerable<ClassFactoryElement>
    {
        public ClassFactoryCollection()
        {
            AddElementName = "Factory";
        }

        protected override ConfigurationElement CreateNewElement()
        {
            return new ClassFactoryElement();
        }

        protected override object GetElementKey(ConfigurationElement element)
        {
            return ((ClassFactoryElement)element).Type;
        }

        public ClassFactoryElement this[int index]
        {
            get
            {
                return (ClassFactoryElement)BaseGet(index);
            }
        }
        public new ClassFactoryElement this[string index]
        {
            get
            {
                return (ClassFactoryElement)BaseGet(index);
            }
        }

        IEnumerator<ClassFactoryElement> IEnumerable<ClassFactoryElement>.GetEnumerator()
        {
            var keys = BaseGetAllKeys();
            foreach (var key in keys)
            {
                var i = (ClassFactoryElement)BaseGet(key);
                if (i != null)
                    yield return i;
            }

        }
    }
    public class ClassFactorySection : ConfigurationSection
    {
        [ConfigurationProperty("", IsRequired = false, IsDefaultCollection = true)]
        public ClassFactoryCollection ClassFactories
        {
            get
            {
                return (ClassFactoryCollection)this[""];
            }
        }
    }
    //ncrunch: no coverage end
}
<file_sep>﻿// Tech-F Framework
// (C) Copyright 2014 <NAME><<EMAIL>>
//
// All rights reserved.This program and the accompanying materials
// are made available under the terms of the GNU Lesser General Public License
// (LGPL) version 2.1 which accompanies this distribution, and is available at
// http://www.gnu.org/licenses/lgpl-2.1.html
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the GNU
// Lesser General Public License for more details.
//
// Contributors:
//     <NAME><<EMAIL>>
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TechF.Test
{
    //ncrunch: no coverage start
    public enum TestEnum
    {
        Test1 = 0,
        Test2 = 1,
        Test3 = 2,
        Test4 = 3
    }
    static class TestClassPropertyValues
    {
        public const string StringProperty = "test";
        public const bool BooleanProperty = true;
        public const sbyte SignedByteProperty = 45;
        public const byte UnsignedByteProperty = 210;
        public const short SignedShortProperty = 2124;
        public const ushort UnsignedShortProperty = 3986;
        public const int SignedIntProperty = 849829;
        public const uint UnsignedIntProperty = 898099;
        public const long SignedLongProperty = 382918301;
        public const ulong UnsignedLongProperty = 382918301;
        public const float SingleProperty = 494.58f;
        public const double DoubleProperty = 890.112;
        public const decimal DecimalProperty = 123.456M;
        public const TestEnum EnumProperty = TestEnum.Test3;
        public static DateTimeOffset DateTimeOffsetProperty = new DateTimeOffset(1988, 2, 11, 0, 0, 0, TimeSpan.FromSeconds(0));
        public static DateTime DateTimeProperty = new DateTime(1988, 2, 11, 0, 0, 0);
    }
    public class TestClass
    {
        public string StringProperty { get; set; }
        public bool BooleanProperty { get; set; }
        public SByte SignedByteProperty { get; set; }
        public Byte UnsignedByteProperty { get; set; }
        public short SignedShortProperty { get; set; }
        public ushort UnsignedShortProperty { get; set; }
        public int SignedIntProperty { get; set; }
        public uint UnsignedIntProperty { get; set; }
        public long SignedLongProperty { get; set; }
        public ulong UnsignedLongProperty { get; set; }
        public float SingleProperty { get; set; }
        public double DoubleProperty { get; set; }
        public decimal DecimalProperty { get; set; }
        public TestEnum EnumProperty { get; set; }
        public TestEnum EnumPropertyNumeric { get; set; }
        public object NullProperty { get; set; }
        public DateTime DateTimeProperty { get; set; }
        public DateTimeOffset DateTimeOffsetProperty { get; set; }
    }
    public class TestClass2
    {
    }
    public class TestClass3 : TestClass
    {
    }
    public class TestClassConstructorInjectionValue
    {
        public int Property { get; private set; }

        public TestClassConstructorInjectionValue(int SignedIntProperty)
        {
            Property = SignedIntProperty;
        }
    }

    public class TestClassNoPublicConstructor
    {
        private TestClassNoPublicConstructor() { }
    }

    public class TestClassConstructiorInjectionRef
    {
        public TestClass Test { get; private set; }

        public TestClassConstructiorInjectionRef(TestClass test)
        {
            Test = test;
        }
    }

    public class ClassFactoryContextTests
    {
        private ImmutableDictionary<string, string> CreateProperties()
        {
            return ImmutableDictionary<string, string>.Empty
                .Add("StringProperty",TestClassPropertyValues.StringProperty)
                .Add("BooleanProperty", TestClassPropertyValues.BooleanProperty.ToString())
                .Add("SignedByteProperty", TestClassPropertyValues.SignedByteProperty.ToString())
                .Add("UnsignedByteProperty", TestClassPropertyValues.UnsignedByteProperty.ToString())
                .Add("SignedShortProperty", TestClassPropertyValues.SignedShortProperty.ToString())
                .Add("UnsignedShortProperty", TestClassPropertyValues.UnsignedShortProperty.ToString())
                .Add("SignedIntProperty", TestClassPropertyValues.SignedIntProperty.ToString())
                .Add("UnsignedIntProperty", TestClassPropertyValues.UnsignedIntProperty.ToString())
                .Add("SignedLongProperty", TestClassPropertyValues.SignedLongProperty.ToString())
                .Add("UnsignedLongProperty", TestClassPropertyValues.UnsignedLongProperty.ToString())
                .Add("SingleProperty", TestClassPropertyValues.SingleProperty.ToString())
                .Add("DoubleProperty", TestClassPropertyValues.DoubleProperty.ToString())
                .Add("DecimalProperty", TestClassPropertyValues.DecimalProperty.ToString())
                .Add("EnumProperty", TestClassPropertyValues.EnumProperty.ToString())
                .Add("NullProperty", null)
                .Add("EnumPropertyNumeric", ((int)TestClassPropertyValues.EnumProperty).ToString())
                .Add("DateTimeOffsetProperty", TestClassPropertyValues.DateTimeOffsetProperty.ToString())
                .Add("DateTimeProperty", TestClassPropertyValues.DateTimeProperty.ToString());
        }
        private TType CreateWithProperties<TType, TImplementation>(bool persist = false) where TType : class where TImplementation : TType
        {
            var context = new ClassFactoryContext();
            var props = CreateProperties();
            context.SetFactoryType<TType, TImplementation>(props).Persist = persist;
            return context.Resolve<TType>();
        }

        [Test]
        public void TestFromGlobal()
        {
            ClassFactory.SetFactoryType<TestClass, TestClass>();
            var context = new ClassFactoryContext();
            var o = context.Resolve<TestClass>();
            ClassFactory.ClearFactoryTypeInformation<TestClass>();
            Assert.IsInstanceOf<TestClass>(o);
        }

        [Test]
        [ExpectedException(typeof(TechF.Exceptions.ClassFactoryException))]
        public void TestNonConfiguredType()
        {
            ClassFactory.ClearFactoryTypeInformation<TestClass>();
            var context = new ClassFactoryContext();
            var o = context.Resolve<TestClass>();
        }

        [Test]
        [ExpectedException(typeof(TechF.Exceptions.ClassFactoryConstructorException))]
        public void TestTypeWithoutPublicConstructor()
        {
            var context = new ClassFactoryContext();
            context.SetFactoryType<TestClassNoPublicConstructor, TestClassNoPublicConstructor>();
            var o = context.Resolve<TestClassNoPublicConstructor>();
        }
        [Test]
        public void TestContextPersistence()
        {
            var context = new ClassFactoryContext();
            context.SetFactoryType<TestClass, TestClass>(null).Persist = true;
            var testClass1 = context.Resolve<TestClass>();
            var testClass2 = context.Resolve<TestClass>();

            Assert.AreSame(testClass1, testClass2);
        }
        [Test]
        public void TestContextNonPersistence()
        {
            var context = new ClassFactoryContext();
            context.SetFactoryType<TestClass, TestClass>(null).Persist = false;
            var testClass1 = context.Resolve<TestClass>();
            var testClass2 = context.Resolve<TestClass>();

            Assert.AreNotSame(testClass1, testClass2);
        }
        [Test]
        [ExpectedException(typeof(Exceptions.ClassFactoryTypeMismatchException))]
        public void TestSetFactoryTypeTypeMismatch()
        {
            var props = CreateProperties();
            var context = new ClassFactoryContext();
            context.SetFactoryType(typeof(TestClass), typeof(TestClass2), null);
        }
        [Test]
        public void TestSetFactoryInheritance()
        {
            var context = new ClassFactoryContext();
            context.SetFactoryType(typeof(TestClass), typeof(TestClass3), null);
        }
        [Test]
        public void TestPropertyBindingString()
        {
            var o = CreateWithProperties<TestClass, TestClass>();
            Assert.AreEqual(o.StringProperty, TestClassPropertyValues.StringProperty);
        }
        [Test]
        public void TestPropertyBindingBoolean()
        {
            var o = CreateWithProperties<TestClass, TestClass>();
            Assert.AreEqual(o.BooleanProperty, TestClassPropertyValues.BooleanProperty);
        }
        [Test]
        public void TestPropertyBindingSignedByte()
        {
            var o = CreateWithProperties<TestClass, TestClass>();
            Assert.AreEqual(o.SignedByteProperty, TestClassPropertyValues.SignedByteProperty);
        }
        [Test]
        public void TestPropertyBindingUnsignedByte()
        {
            var o = CreateWithProperties<TestClass, TestClass>();
            Assert.AreEqual(o.UnsignedByteProperty, TestClassPropertyValues.UnsignedByteProperty);
        }
        [Test]
        public void TestPropertyBindingSignedShort()
        {
            var o = CreateWithProperties<TestClass, TestClass>();
            Assert.AreEqual(o.SignedShortProperty, TestClassPropertyValues.SignedShortProperty);
        }
        [Test]
        public void TestPropertyBindingUnsignedShort()
        {
            var o = CreateWithProperties<TestClass, TestClass>();
            Assert.AreEqual(o.SignedShortProperty, TestClassPropertyValues.SignedShortProperty);
        }
        [Test]
        public void TestPropertyBindingSignedInt()
        {
            var o = CreateWithProperties<TestClass, TestClass>();
            Assert.AreEqual(o.SignedIntProperty, TestClassPropertyValues.SignedIntProperty);
        }
        [Test]
        public void TestPropertyBindingUnsignedInt()
        {
            var o = CreateWithProperties<TestClass, TestClass>();
            Assert.AreEqual(o.UnsignedIntProperty, TestClassPropertyValues.UnsignedIntProperty);
        }
        [Test]
        public void TestPropertyBindingSignedLong()
        {
            var o = CreateWithProperties<TestClass, TestClass>();
            Assert.AreEqual(o.SignedLongProperty, TestClassPropertyValues.SignedLongProperty);
        }
        [Test]
        public void TestPropertyBindingUnsignedLong()
        {
            var o = CreateWithProperties<TestClass, TestClass>();
            Assert.AreEqual(o.UnsignedLongProperty, TestClassPropertyValues.UnsignedLongProperty);
        }
        [Test]
        public void TestPropertyBindingSingle()
        {
            var o = CreateWithProperties<TestClass, TestClass>();
            Assert.AreEqual(o.SingleProperty, TestClassPropertyValues.SingleProperty);
        }
        [Test]
        public void TestPropertyBindingDouble()
        {
            var o = CreateWithProperties<TestClass, TestClass>();
            Assert.AreEqual(o.DoubleProperty, TestClassPropertyValues.DoubleProperty);
        }
        [Test]
        public void TestPropertyBindingDecimal()
        {
            var o = CreateWithProperties<TestClass, TestClass>();
            Assert.AreEqual(o.DecimalProperty, TestClassPropertyValues.DecimalProperty);
        }
        [Test]
        public void TestPropertyEnum()
        {
            var o = CreateWithProperties<TestClass, TestClass>();
            Assert.AreEqual(o.EnumProperty, TestClassPropertyValues.EnumProperty);
        }
        [Test]
        public void TestPropertyEnumNumeric()
        {
            var o = CreateWithProperties<TestClass, TestClass>();
            Assert.AreEqual(o.EnumPropertyNumeric, TestClassPropertyValues.EnumProperty);
        }
        [Test]
        public void TestPropertyNull()
        {
            var o = CreateWithProperties<TestClass, TestClass>();
            Assert.AreEqual(o.NullProperty, null);
        }
        [Test]
        public void TestPropertyDateTime()
        {
            var o = CreateWithProperties<TestClass, TestClass>();
            Assert.AreEqual(o.DateTimeProperty, TestClassPropertyValues.DateTimeProperty);
        }
        [Test]
        public void TestPropertyDateTimeOffset()
        {
            var o = CreateWithProperties<TestClass, TestClass>();
            Assert.AreEqual(o.DateTimeOffsetProperty, TestClassPropertyValues.DateTimeOffsetProperty);
        }

        [Test]
        public void TestConstructorInjectionValues()
        {
            var o = CreateWithProperties<TestClassConstructorInjectionValue, TestClassConstructorInjectionValue>();
            Assert.AreEqual(TestClassPropertyValues.SignedIntProperty, o.Property);
        }
        [Test]
        [ExpectedException(typeof(Exceptions.ClassFactoryConstructorException))]
        public void TestConstructorInjectionMissingValues()
        {
            var context = new ClassFactoryContext();
            var props = ImmutableDictionary<string, string>.Empty;
            context.SetFactoryType<TestClassConstructorInjectionValue, TestClassConstructorInjectionValue>(props);
            context.Resolve<TestClassConstructorInjectionValue>();
        }
        [Test]
        public void TestConstructorInjectionResolve()
        {
            var context = new ClassFactoryContext();
            context.SetFactoryType<TestClass, TestClass>();
            context.SetFactoryType<TestClassConstructiorInjectionRef, TestClassConstructiorInjectionRef>();
            var o = context.Resolve<TestClassConstructiorInjectionRef>();
            Assert.NotNull(o.Test);
        }
        [Test]
        public void TestNoPropertyBinding()
        {
            var context = new ClassFactoryContext();
            var props = ImmutableDictionary<string, string>.Empty
                .Add("StringProperty", TestClassPropertyValues.StringProperty);
            context.SetFactoryType<TestClass, TestClass>(props).BindProperties = false;
            var o = context.Resolve<TestClass>();
            Assert.AreNotEqual(o.StringProperty, TestClassPropertyValues.StringProperty);
        }

        [Test]
        [ExpectedException(typeof(Exceptions.ClassFactoryTypeMismatchException))]
        public void TestTypeMismatch()
        {
            var context = new ClassFactoryContext();
            context.SetFactoryType(typeof(TestClass3), typeof(TestClass));
        }

        [Test]
        public void TestGetTypeOptions()
        {
            var context = new ClassFactoryContext();
            context.SetFactoryType<TestClass, TestClass>();
            context.GetTypeOptions<TestClass>().BindProperties = false;
            var o = context.Resolve<TestClass>();
            Assert.AreNotEqual(TestClassPropertyValues.StringProperty, o.StringProperty);
        }
        [Test]
        public void TestGetTypeOptionsFromRoot()
        {
            var context = new ClassFactoryContext();
            ClassFactory.SetFactoryType<TestClass, TestClass>();
            context.GetTypeOptions<TestClass>().BindProperties = false;
            var o = context.Resolve<TestClass>();
            Assert.AreNotEqual(TestClassPropertyValues.StringProperty, o.StringProperty);
        }
        [Test]
        [ExpectedException(typeof(Exceptions.ClassFactoryTypeMismatchException))]
        public void TestGetTypeOptionsFromInvalidType()
        {
            ClassFactory.ClearFactoryTypeInformation<TestClass>();
            new ClassFactoryContext().GetTypeOptions<TestClass>();
        }
        [Test]
        [ExpectedException(typeof(Exceptions.ClassFactoryException))]
        public void TestClearTypeInformation()
        {
            var context = new ClassFactoryContext();
            ClassFactory.ClearFactoryTypeInformation<TestClass>();
            context.SetFactoryType<TestClass, TestClass>();
            context.ClearFactoryTypeInformation<TestClass>();
            context.Resolve<TestClass>();
        }
    }
    //ncrunch: no coverage end
}
<file_sep>﻿// Tech-F Framework
// (C) Copyright 2014 <NAME><<EMAIL>>
//
// All rights reserved.This program and the accompanying materials
// are made available under the terms of the GNU Lesser General Public License
// (LGPL) version 2.1 which accompanies this distribution, and is available at
// http://www.gnu.org/licenses/lgpl-2.1.html
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the GNU
// Lesser General Public License for more details.
//
// Contributors:
//     <NAME><<EMAIL>>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TechF.Exceptions
{
    public class ValidationError : Exception
    {
        //ncrunch: no coverage start
        private string[] _errors;

        public ValidationError(IEnumerable<string> errors)
        {
            _errors = errors.ToArray();
        }

        public override string ToString()
        {
            return string.Join("\n", _errors);
        }
        //ncrunch: no coverage end
    }
}
<file_sep>﻿// Tech-F Framework
// (C) Copyright 2014 <NAME><<EMAIL>>
//
// All rights reserved.This program and the accompanying materials
// are made available under the terms of the GNU Lesser General Public License
// (LGPL) version 2.1 which accompanies this distribution, and is available at
// http://www.gnu.org/licenses/lgpl-2.1.html
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the GNU
// Lesser General Public License for more details.
//
// Contributors:
//     <NAME><<EMAIL>>
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace TechF
{
    public class ClassFactoryContext : IDisposable
    {
        private Dictionary<System.Type, ClassFactoryBinder> _factories = new Dictionary<Type, ClassFactoryBinder>();
        internal ReaderWriterLock _factoriesLock = new ReaderWriterLock();

        private ClassFactoryBinder ResolveRoot(Type type)
        {
            ClassFactory._factoriesLock.AcquireReaderLock(-1);
            var binder = ClassFactory._factories.ContainsKey(type) ? ClassFactory._factories[type] : null;
            ClassFactory._factoriesLock.ReleaseReaderLock();
            return binder;
        }
        private ClassFactoryBinder ResolveContext(Type type)
        {
            _factoriesLock.AcquireReaderLock(-1);
            var binder = _factories.ContainsKey(type) ? _factories[type] : null;
            _factoriesLock.ReleaseReaderLock();
            return binder;
        }

        /// <summary>
        /// Resolve a object of the specified type from the context,
        /// falling back to the global class factory if not found in the context.
        /// If resolved from the global class factory, the 
        /// configuration is added to the context
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        /// <throws name="ClassFactoryTypeMismatch">If the type is not configured or valid for creation</throws>
        public object Resolve(Type type)
        {
            ClassFactoryBinder binder = ResolveContext(type);
            if (binder != null)
            {
                var o = binder.Create();
                return o;
            }
            binder = ResolveRoot(type);
            if (binder != null)
            {
                var contextBinder = new ClassFactoryBinder(this, binder);
                _factoriesLock.AcquireWriterLock(-1);
                _factories[binder._type] = contextBinder;
                _factoriesLock.ReleaseWriterLock();
                return contextBinder.Create();
            }
            throw new Exceptions.ClassFactoryException(string.Format("Type '{0}' is not configured", type.Name));
        }
        /// <summary>
        /// Resolve a object of the specified type from the context,
        /// falling back to the global class factory if not found in the context.
        /// If resolved from the global class factory, the 
        /// configuration is added to the context
        /// </summary>
        /// <typeparam name="T">The type to create</typeparam>
        /// <returns>A object of the requested type</returns>
        /// <throws name="ClassFactoryTypeMismatch">If the type is not configured or valid for creation</throws>
        public T Resolve<T>() where T : class
        {
            return (T)Resolve(typeof(T));
        }
        /// <summary>
        /// Configure a context bound factory for the given type using the provided 
        /// constant values used in constructor injection and property binding
        /// </summary>
        /// <param name="type">The type to configure</param>
        /// <param name="factoryType">The type that implements 'type'</param>
        /// <param name="properties">Constant properties for parameter binding and constructor injection</param>
        /// <returns>A options object that can be used for setting persistence and property binding</returns>
        public ClassFactoryOptions SetFactoryType(Type type, Type factoryType, ImmutableDictionary<string, string> properties = null)
        {
            if (!type.IsAssignableFrom(factoryType))
                throw new Exceptions.ClassFactoryTypeMismatchException();

            var binder = new ClassFactoryBinder(this, factoryType, properties);

            _factoriesLock.AcquireWriterLock(-1);
            _factories[type] = binder;
            _factoriesLock.ReleaseWriterLock();

            return binder._options;
        }
        /// <summary>
        /// Configure a context bound factory for the given type using the provided 
        /// constant values used in constructor injection and property binding
        /// </summary>
        /// <param name="type">The type to configure</param>
        /// <param name="factoryType">The type that implements 'type'</param>
        /// <param name="properties">Constant properties for parameter binding and constructor injection</param>
        /// <returns>A options object that can be used for setting persistence and property binding</returns>
        public ClassFactoryOptions SetFactoryType<TType, TImplementation>(ImmutableDictionary<string, string> properties = null) where TType : class where TImplementation : TType
        {
            return SetFactoryType(typeof(TType), typeof(TImplementation), properties);
        }
        /// <summary>
        /// Get the options object for the specified type, in order to set persistence and property binding 
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public ClassFactoryOptions GetTypeOptions(Type type)
        {
            ClassFactoryBinder binder = ResolveContext(type);
            if (binder != null)
                return binder._options;
            binder = ResolveRoot(type);
            if (binder != null)
                return binder._options;
            throw new Exceptions.ClassFactoryTypeMismatchException();
        }
        /// <summary>
        /// Get the options object for the specified type, in order to set persistence and property binding 
        /// </summary>
        /// <typeparam name="type"></typeparam>
        /// <returns></returns>
        public ClassFactoryOptions GetTypeOptions<T>()
        {
            return GetTypeOptions(typeof(T));
        }
        /// <summary>
        /// Remove the configuration for the specified type
        /// </summary>
        /// <param name="type"></param>
        public void ClearFactoryTypeInformation(Type type)
        {
            _factoriesLock.AcquireWriterLock(-1);
            if (_factories.ContainsKey(type))
                _factories.Remove(type);
            _factoriesLock.ReleaseWriterLock();
        }
        /// <summary>
        /// Remove the configuration for the specified type
        /// </summary>
        /// <typeparam name="type"></typeparam>
        public void ClearFactoryTypeInformation<T>()
        {
            ClearFactoryTypeInformation(typeof(T));
        }

        //ncrunch: no coverage start
        public void Dispose()
        {
        }
        //ncrunch: no coverage end
    }
}
<file_sep>﻿// Tech-F Framework
// (C) Copyright 2014 <NAME><<EMAIL>>
//
// All rights reserved.This program and the accompanying materials
// are made available under the terms of the GNU Lesser General Public License
// (LGPL) version 2.1 which accompanies this distribution, and is available at
// http://www.gnu.org/licenses/lgpl-2.1.html
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the GNU
// Lesser General Public License for more details.
//
// Contributors:
//     <NAME><<EMAIL>>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TechF.Configuration
{
    //ncrunch: no coverage start
    public static class ConfigurationManager
    {
        public static IClassFactoryConfiguration Copy(this ClassFactorySection config)
        {
            if (config == null)
                return null;

            return new ClassFactoryConfiguration()
            {
                ClassFactories
                    = from c in config.ClassFactories ?? new ClassFactoryCollection()
                      select new ClassFactory()
                      {
                          Type = c.Type,
                          PersistPerContext = c.PersistsPerContext,
                          FactoryType = c.FactoryType,
                          FactoryProperties = from p in c.FactoryProperties ?? new ClassFactoryPropertyCollection()
                                              select new ClassFactoryProperty()
                                              {
                                                  Name = p.Name,
                                                  Value = p.Value
                                              }}};
        }
        public static IClassFactoryConfiguration ClassFactoryConfigurationFromConfigurationFile(string section)
        {
            return ((ClassFactorySection)System.Configuration.ConfigurationManager.GetSection(section)).Copy();
        }
    }
    //ncrunch: no coverage end
}
<file_sep>﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TechF.Utilities
{
    public class DictionaryComparison<TKey, TValue> where TValue : class
    {
        public static bool Compare(IReadOnlyDictionary<TKey, TValue> x, IReadOnlyDictionary<TKey, TValue> y)
        {
            //
            if (null == y)
                return null == x;
            if (null == x)
                return false;
            if (object.ReferenceEquals(x, y))
                return true;
            if (x.Count != y.Count)
                return false;
            foreach (TKey k in x.Keys)
                if (!y.ContainsKey(k))
                    return false;

            //
            foreach (TKey k in x.Keys)
            {
                var xk = x != null ? x[k] : null;
                var yk = y != null ? y[k] : null;

                if (xk == null && yk != null)
                    return false;

                if (xk != yk)
                    return false;
            }

            return true;
        }
    }
}
<file_sep>Tech-F
======
General Purpose Utility Framework
---------------------------------

Currently only contains a class factory implementation which generates IL dynamically 
to enable the fastest available performance when resolving objects. The generated code
handles constructor injection and property binding automatically, and allows an entire
application and its dependencies be loaded automatically using app.config or web.config
or programmatically.

**Three example projects are provided which demonstrates is usage**

**TechF.Example.BasicUsage** demonstrates simple programmatic usage, with constructor
injection and property binding.

**TechF.Examples.BasicUsageConfiguration** demonstrates app.config based factory configuration
with constructor injection and property binding

**TechF.Examples.BasicWebApi** demonstrates using the class factory to implement IDependencyResolver
and allow the class factory to construct WebApi controllers with constructor
injection and property binding


<file_sep>﻿// Tech-F Framework
// (C) Copyright 2014 <NAME><<EMAIL>>
//
// All rights reserved.This program and the accompanying materials
// are made available under the terms of the GNU Lesser General Public License
// (LGPL) version 2.1 which accompanies this distribution, and is available at
// http://www.gnu.org/licenses/lgpl-2.1.html
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the GNU
// Lesser General Public License for more details.
//
// Contributors:
//     <NAME><<EMAIL>>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;

namespace TechF.Examples.BasicWebApi
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Load class factory configuration from web.config
            // Allows web.config to be the entry point for the
            // application, and making it easy to deploy variations
            // of the applications
            var classFactoryConfig = TechF.Configuration.ConfigurationManager.ClassFactoryConfigurationFromConfigurationFile("ClassFactory");
            ClassFactory.LoadFromConfiguration(classFactoryConfig);
            config.DependencyResolver = new DependencyResolver();

            // Web API routes
            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
        }
    }
}
<file_sep>﻿// Tech-F Framework
// (C) Copyright 2014 <NAME><<EMAIL>>
//
// All rights reserved.This program and the accompanying materials
// are made available under the terms of the GNU Lesser General Public License
// (LGPL) version 2.1 which accompanies this distribution, and is available at
// http://www.gnu.org/licenses/lgpl-2.1.html
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the GNU
// Lesser General Public License for more details.
//
// Contributors:
//     <NAME><<EMAIL>>
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TechF.Test
{
    //ncrunch: no coverage start
    public class ClassFactoryTests
    {
        [Test]
        public void TestResolve()
        {
            ClassFactory.SetFactoryType<TestClass, TestClass>();
            var o = ClassFactory.Resolve<TestClass>();
        }
        [Test]
        [ExpectedException(typeof(Exceptions.ClassFactoryTypeMismatchException))]
        public void TestTypeMismatch()
        {
            ClassFactory.SetFactoryType(typeof(TestClass3), typeof(TestClass));
        }
        [Test]
        public void ResolveTwice()
        {
            ClassFactory.SetFactoryType<TestClass, TestClass>();
            var o1 = ClassFactory.Resolve<TestClass>();
            var o2 = ClassFactory.Resolve<TestClass>();
            Assert.NotNull(o1);
            Assert.NotNull(o2);
        }
        [Test]
        [ExpectedException(typeof(Exceptions.ClassFactoryTypeMismatchException))]
        public void ResolveNonConfiguredType()
        {
            ClassFactory.Resolve<TestClass2>();
        }
    }
    //ncrunch: no coverage end
}
<file_sep>﻿ // Tech-F Framework
 // (C) Copyright 2014 <NAME><<EMAIL>>
 //
 // All rights reserved.This program and the accompanying materials
 // are made available under the terms of the GNU Lesser General Public License
 // (LGPL) version 2.1 which accompanies this distribution, and is available at
 // http://www.gnu.org/licenses/lgpl-2.1.html
 //
 // This library is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the GNU
 // Lesser General Public License for more details.
 //
 // Contributors:
 //     <NAME><<EMAIL>>
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TechF.Example.BasicUsage
{
    public interface IDummyDataSource
    {
        string Text { get; }
    }
    public interface IDummyService
    {
        void Speak();
    }
    public class DummyDataSource : IDummyDataSource
    {
        // This property will be set automatically using property binding.
        public string Text { get; set; }
    }
    public class DummyService : IDummyService
    {
        private IDummyDataSource _dataSource;

        public DummyService(IDummyDataSource dataSource)
        {
            // The class factory generated code will automatically
            // resolve reference types (besides string) using the class
            // factory context. Value types will be resolved by parameter name
            // in the property object provided on type configuration
            _dataSource = dataSource;
        }
        
        public void Speak()
        {
            Console.WriteLine(_dataSource.Text);
        }
    }


    // This is the main class for the application.
    // By keeping a class which references all the major components,
    // it is possible for the class factory to construct all depenncies
    // and types automatically without the components needing to know 
    // about the class factory. This lets you reuse your entire application
    // without being dependent on the class factory
    public class Application
    {
        
        private IDummyService _service;

        public Application(IDummyService service)
        {
            _service = service;
        }

        public void Run()
        {
            _service.Speak();
            Console.WriteLine("Press any key to continue...");
            Console.ReadKey();
        }

        public static void Main(string[] args)
        {
            // Enter Class Factory context
            using(var context = new ClassFactoryContext())
            {
                // Create property dictionary to use for
                // setting constructor argument and applying
                // property binding
                var props = ImmutableDictionary<string, string>.Empty.Add("Text", "Hello world!");
                // Initialize IDummyDataSource to use the DummyDataSource
                // implementation using the provided properties for property
                // binding the Text property (properties are bound when they
                // have a public set accesor)
                context.SetFactoryType<IDummyDataSource, DummyDataSource>(props);
                // Initialize IDummyService to use the DummyService
                // implementation. The constructor argument dataSource
                // is resolved using the class factory context on constructor 
                // call time
                context.SetFactoryType<IDummyService, DummyService>();
                // Initialize the main class Application. Application
                // should have all needed services required as constructor
                // arguments, so the class factory can initialize the entire
                // application without any need to call the class factory
                // later on in the application. This allows complete decoupling
                // of the class factory component from the rest of the application
                context.SetFactoryType<Application, Application>();
                
                // Resolve the application object from the class factory
                var application = context.Resolve<Application>();
                // Run the application
                application.Run();
            }
        }
    }
}
<file_sep>﻿// Tech-F Framework
// (C) Copyright 2014 <NAME><<EMAIL>>
//
// All rights reserved.This program and the accompanying materials
// are made available under the terms of the GNU Lesser General Public License
// (LGPL) version 2.1 which accompanies this distribution, and is available at
// http://www.gnu.org/licenses/lgpl-2.1.html
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the GNU
// Lesser General Public License for more details.
//
// Contributors:
//     <NAME><<EMAIL>>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace TechF.CodeGeneration
{
    public static class ClassFactoryCodeGenerator
    {
        internal class TypeCodeCacheEntry
        {
            public Type Type { get; set; }
            public ConstructorCall ConstructorCall { get; set; }
            public PropertyBinder PropertyBinder { get; set; }
            public IReadOnlyDictionary<string, string> Properties { get; set; }
            public int FetchCount { get; set; }
        }
        private static Dictionary<Type, IList<TypeCodeCacheEntry>> _typeCodeCache = new Dictionary<Type, IList<TypeCodeCacheEntry>>();
        private static ReaderWriterLock _typeCodeCacheLock = new ReaderWriterLock();

        internal static TypeCodeCacheEntry GetCachedItem(Type type, IReadOnlyDictionary<string, string> props)
        {
            IList<TypeCodeCacheEntry> list = new List<TypeCodeCacheEntry>();
            _typeCodeCacheLock.AcquireReaderLock(-1);
            if(_typeCodeCache.ContainsKey(type))
                list = _typeCodeCache[type];
            _typeCodeCacheLock.ReleaseReaderLock();

            var item = (from c in list where Utilities.DictionaryComparison<string, string>.Compare(c.Properties, props) select c).FirstOrDefault();
            if(item == null)
                item =  Cache(type, props);
            return item;
        }
        internal static TypeCodeCacheEntry Cache(Type type, IReadOnlyDictionary<string, string> props)
        {
            var ctorCall = CreateConstructorInvokeMethod(type, props);
            var propBinder = CreatePropertyBinder(type, props);

            return CacheItem(type, props, ctorCall, propBinder);
        }
        private static TypeCodeCacheEntry CacheItem(Type type, IReadOnlyDictionary<string, string> props, ConstructorCall ctorCall, PropertyBinder propBinder)
        {
            _typeCodeCacheLock.AcquireWriterLock(-1);
            IList<TypeCodeCacheEntry> list = null;
            if(_typeCodeCache.ContainsKey(type))
            {
                list = _typeCodeCache[type];
            } else
            {
                list = new List<TypeCodeCacheEntry>();
                _typeCodeCache.Add(type, list);
            }
            var entry = new TypeCodeCacheEntry()
            {
                Type = type,
                ConstructorCall = ctorCall,
                PropertyBinder = propBinder,
                Properties = props,
                FetchCount = 0
            };
            list.Add(entry);
            _typeCodeCacheLock.ReleaseWriterLock();

            return entry;
        }

        public delegate void PropertyBinder(object obj);
        public delegate object ConstructorCall(ClassFactoryContext context);

        private static void NullBinder(object obj) { }

        private static void EmitDateTime(ILGenerator il, string value)
        {
            var method = typeof(DateTime).GetMethod("Parse", new Type[] { typeof(string) });
            il.Emit(OpCodes.Ldstr, value);
            il.Emit(OpCodes.Call, method);
        }
        private static void EmitDateTimeOffset(ILGenerator il, string value)
        {
            var method = typeof(DateTimeOffset).GetMethod("Parse", new Type[] { typeof(string) });
            il.Emit(OpCodes.Ldstr, value);
            il.Emit(OpCodes.Call, method);
        }
        private static void EmitEnum(ILGenerator il, Type type, string value)
        {
            object enumObj = Enum.Parse(type, value, true);
            int i = (int)enumObj;
            il.Emit(OpCodes.Ldc_I4, i);
        }
        private static void EmitDecimal(ILGenerator il, string value)
        {
            var method = typeof(Decimal).GetMethod("Parse", new Type[] { typeof(string) });
            il.Emit(OpCodes.Ldstr, value);
            il.Emit(OpCodes.Call, method);
        }

        private static bool EmitPropertyValue(ILGenerator il, Type type, string value)
        {
            if (type == typeof(string))
                il.Emit(OpCodes.Ldstr, value);
            else if (type == typeof(byte) || type == typeof(ushort) || type == typeof(uint))
                il.Emit(OpCodes.Ldc_I4, Convert.ToUInt32(value));
            else if (type == typeof(sbyte) || type == typeof(short) || type == typeof(int))
                il.Emit(OpCodes.Ldc_I4, Convert.ToInt32(value));
            else if (type == typeof(long))
                il.Emit(OpCodes.Ldc_I8, Convert.ToInt64(value));
            else if (type == typeof(ulong))
                il.Emit(OpCodes.Ldc_I8, unchecked((long)Convert.ToUInt64(value)));
            else if (type == typeof(bool))
                il.Emit(OpCodes.Ldc_I4, Convert.ToBoolean(value) ? 1 : 0);
            else if (type == typeof(float))
                il.Emit(OpCodes.Ldc_R4, Convert.ToSingle(value));
            else if (type == typeof(double))
                il.Emit(OpCodes.Ldc_R8, Convert.ToDouble(value));
            else if (type == typeof(decimal))
                EmitDecimal(il, value);
            else if (type == typeof(DateTime))
                EmitDateTime(il, value);
            else if (type == typeof(DateTimeOffset))
                EmitDateTimeOffset(il, value);
            else if (type.IsEnum)
                //
                EmitEnum(il, type, value);
            return true;
        }

        public static PropertyBinder CreatePropertyBinder(Type type, IReadOnlyDictionary<string, string> props)
        {
            props = props ?? new Dictionary<string, string>();
            if (props.Count < 1)
                return NullBinder;
            var properties = type.GetProperties().Where(x => x.SetMethod.IsPublic).ToArray();
            if (properties.Length < 1)
                return NullBinder;

            var method = new DynamicMethod("", null, new Type[] { typeof(object) });
            var il = method.GetILGenerator();

            var obj = il.DeclareLocal(type);
            var propertyLocals = new LocalBuilder[properties.Length];
            for (int i = 0; i < properties.Length; i++)
                propertyLocals[i] = il.DeclareLocal(properties[i].PropertyType);
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Castclass, type);
            il.Emit(OpCodes.Stloc, obj);



            for (int i = 0; i < properties.Length; i++)
            {
                var property = properties[i];
                if (!(property.PropertyType == typeof(string) || property.PropertyType.IsValueType))
                    continue;
                if (props.ContainsKey(property.Name))
                {
                    if (EmitPropertyValue(il, property.PropertyType, props[property.Name]))
                    {
                        il.Emit(OpCodes.Stloc, propertyLocals[i]);
                        il.Emit(OpCodes.Ldloc, obj);
                        il.Emit(OpCodes.Ldloc, propertyLocals[i]);
                        il.Emit(OpCodes.Call, property.SetMethod);
                    }
                }
            }
            il.Emit(OpCodes.Ret);

            return (PropertyBinder)method.CreateDelegate(typeof(PropertyBinder));
        }

        public static ConstructorCall CreateConstructorInvokeMethod(Type type, IReadOnlyDictionary<string, string> props)
        {
            var method = new DynamicMethod("", typeof(object), new Type[] { typeof(ClassFactoryContext) });
            var il = method.GetILGenerator();
            foreach (var ctor in type.GetConstructors())
            {
                if (!ctor.IsPublic) continue;
                bool resolvedValueParameters = true;
                foreach (var param in ctor.GetParameters())
                    if ((param.ParameterType.IsValueType || param.ParameterType == typeof(string)) && !props.ContainsKey(param.Name))
                    {
                        resolvedValueParameters = false;
                        break;
                    }
                if (resolvedValueParameters)
                {
                    // This constructor is usable
                    // Generate IL code
                    MethodInfo contextResolveMethod = typeof(ClassFactoryContext).GetMethods().Where(x => x.IsPublic && x.Name == "Resolve" && x.ContainsGenericParameters).Single();
                    MethodInfo globalMethod = typeof(ClassFactory).GetMethods().Where(x => x.Name == "Resolve" && x.ContainsGenericParameters).Single();

                    var parameters = ctor.GetParameters();
                    var paramLocals = new LocalBuilder[parameters.Length];

                    for (int i = 0; i < parameters.Length; i++)
                        paramLocals[i] = il.DeclareLocal(parameters[i].ParameterType);

                    for (int i = 0; i < parameters.Length; i++)
                    {
                        var param = parameters[i];
                        if (param.ParameterType.IsValueType || param.ParameterType == typeof(string))
                        {
                            EmitPropertyValue(il, param.ParameterType, props[param.Name]);
                            il.Emit(OpCodes.Stloc, paramLocals[i]);
                        }
                        else
                        {
                            var labelWithContext = il.DefineLabel();
                            var labelAfterContext = il.DefineLabel();

                            il.Emit(OpCodes.Ldarg_0);
                            il.Emit(OpCodes.Brtrue, labelWithContext);
                            // Without class factory
                            var genericMethod = globalMethod.MakeGenericMethod(new Type[] { param.ParameterType });
                            il.Emit(OpCodes.Call, genericMethod);
                            il.Emit(OpCodes.Stloc, paramLocals[i]);
                            il.Emit(OpCodes.Br, labelAfterContext);
                            il.MarkLabel(labelWithContext);
                            // With class factory context
                            var genericMethodContext = contextResolveMethod.MakeGenericMethod(new Type[] { param.ParameterType });
                            il.Emit(OpCodes.Ldarg_0);
                            il.Emit(OpCodes.Call, genericMethodContext);
                            il.Emit(OpCodes.Stloc, paramLocals[i]);

                            il.MarkLabel(labelAfterContext);
                        }
                    }

                    for (int i = 0; i < parameters.Length; i++)
                        il.Emit(OpCodes.Ldloc, paramLocals[i]);
                    il.Emit(OpCodes.Newobj, ctor);
                    il.Emit(OpCodes.Ret);

                    return (ConstructorCall)method.CreateDelegate(typeof(ConstructorCall));
                }

            }
            throw new Exceptions.ClassFactoryConstructorException("No supported constructors are available");
        }
    }
}
<file_sep>﻿// Tech-F Framework
// (C) Copyright 2014 <NAME><<EMAIL>>
//
// All rights reserved.This program and the accompanying materials
// are made available under the terms of the GNU Lesser General Public License
// (LGPL) version 2.1 which accompanies this distribution, and is available at
// http://www.gnu.org/licenses/lgpl-2.1.html
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the GNU
// Lesser General Public License for more details.
//
// Contributors:
//     <NAME><<EMAIL>>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TechF.Examples.BasicUsageConfiguration
{
    public interface IDummyDataSource
    {
        string Text { get; set; }
    }
    public interface IDummyService
    {
        void Speak();
    }
    public class DummyDataSource : IDummyDataSource
    {
        public string Text { get; set; }
    }
    public class DummyService : IDummyService
    {
        private IDummyDataSource _dataSource;

        public DummyService(IDummyDataSource dataSource)
        {
            _dataSource = dataSource;
        }

        public void Speak()
        {
            Console.WriteLine(_dataSource.Text);
        }
    }

    public class Application
    {
        private IDummyService _service;

        public Application(IDummyService service)
        {
            _service = service;
        }

        public void Run()
        {
            _service.Speak();
            Console.WriteLine("Press any key to continue...");
            Console.ReadKey();
        }

        public static void Main(string[] args)
        {
            var config = TechF.Configuration.ConfigurationManager.ClassFactoryConfigurationFromConfigurationFile("ClassFactory");
            ClassFactory.LoadFromConfiguration(config);
            using (var context = new ClassFactoryContext())
            {
                var application = context.Resolve<Application>();
                application.Run();
            }
        }
    }
}
<file_sep>﻿// Tech-F Framework
// (C) Copyright 2014 <NAME><<EMAIL>>
//
// All rights reserved.This program and the accompanying materials
// are made available under the terms of the GNU Lesser General Public License
// (LGPL) version 2.1 which accompanies this distribution, and is available at
// http://www.gnu.org/licenses/lgpl-2.1.html
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the GNU
// Lesser General Public License for more details.
//
// Contributors:
//     <NAME><<EMAIL>>
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using TechF.Configuration;

namespace TechF
{
    /// <summary>
    /// Global Class Factory singleton. Configures global factories and properties
    /// </summary>
    public class ClassFactory
    {
        //ncrunch: no coverage start
        internal static Dictionary<System.Type, ClassFactoryBinder> _factories = new Dictionary<Type, ClassFactoryBinder>();
        internal static ReaderWriterLock _factoriesLock = new ReaderWriterLock();
        //ncrunch: no coverage end

        private static ClassFactoryBinder ResolveBinder(Type type)
        {
            _factoriesLock.AcquireReaderLock(-1);
            var binder = _factories.ContainsKey(type) ? _factories[type] : null;
            _factoriesLock.ReleaseReaderLock();
            return binder;
        }
        /// <summary>
        /// Resolve a object for the specified type
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static object Resolve(Type type)
        {
            var binder = ResolveBinder(type);
            if(binder != null)
                return binder.Create();
            throw new Exceptions.ClassFactoryTypeMismatchException();
        }
        /// <summary>
        /// Resolve a object for the specified type
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static T Resolve<T>() where T : class
        {
            return (T)Resolve(typeof(T));
        }
        /// <summary>
        /// Remove the configuration for the specified type
        /// </summary>
        /// <param name="type"></param>
        public static void ClearFactoryTypeInformation(Type type)
        {
            _factoriesLock.AcquireWriterLock(-1);
            if (_factories.ContainsKey(type))
                _factories.Remove(type);
            _factoriesLock.ReleaseWriterLock();
        }
        /// <summary>
        /// Remove the configuration for the specified type
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public static void ClearFactoryTypeInformation<T>()
        {
            ClearFactoryTypeInformation(typeof(T));
        }
        /// <summary>
        /// Configure a factory for the given type using the provided 
        /// constant values used in constructor injection and property binding
        /// </summary>
        /// <param name="type">The type to configure</param>
        /// <param name="factoryType">The type that implements 'type'</param>
        /// <param name="properties">Constant properties for parameter binding and constructor injection</param>
        /// <returns>A options object that can be used for setting persistence and property binding</returns>
        public static ClassFactoryOptions SetFactoryType(Type type, Type factoryType, ImmutableDictionary<string, string> properties = null)
        {
            if (!type.IsAssignableFrom(factoryType))
                throw new Exceptions.ClassFactoryTypeMismatchException();
            var binder = new ClassFactoryBinder(null, factoryType, properties);

            _factoriesLock.AcquireWriterLock(-1);
            _factories[type] = binder;
            _factoriesLock.ReleaseWriterLock();

            return binder._options;
        }
        /// <summary>
        /// Configure a factory for the given type using the provided 
        /// constant values used in constructor injection and property binding
        /// </summary>
        /// <typeparam name="TType">The type to configure</typeparam>
        /// <typeparam name="TImplementation">The type that implements 'type'</typeparam>
        /// <param name="properties">Constant properties for parameter binding and constructor injection</param>
        /// <returns>A options object that can be used for setting persistence and property binding</returns>
        public static ClassFactoryOptions SetFactoryType<TType, TImplementation>(ImmutableDictionary<string, string> properties = null) where TType : class where TImplementation : TType
        {
            return SetFactoryType(typeof(TType), typeof(TImplementation), properties);
        }
        //ncrunch: no coverage start
        /// <summary>
        ///  Load class factory configuration
        /// </summary>
        /// <param name="configuration"></param>
        public static void LoadFromConfiguration(IClassFactoryConfiguration configuration)
        {
            foreach (var factory in configuration.ClassFactories)
            {
                var typeName = factory.Type;
                var factoryTypeName = factory.FactoryType;

                var props = factory.FactoryProperties ?? new IClassFactoryProperty[] { };
                ImmutableDictionary<string, string> factoryBinder = props.ToImmutableDictionary(x => x.Name, x => x.Value);

                try
                {
                    Type type = Type.GetType(typeName);
                    Type factoryType = Type.GetType(factoryTypeName);


                    if (type != null &&  factoryType != null && type.IsAssignableFrom(factoryType))
                    {
                        SetFactoryType(type, factoryType, factoryBinder).Persist = factory.PersistPerContext;
                    }
                }
                catch
                {
                }
            }
        }
        //ncrunch: no coverage end
    }
}
<file_sep>﻿// Tech-F Framework
// (C) Copyright 2014 <NAME><<EMAIL>>
//
// All rights reserved.This program and the accompanying materials
// are made available under the terms of the GNU Lesser General Public License
// (LGPL) version 2.1 which accompanies this distribution, and is available at
// http://www.gnu.org/licenses/lgpl-2.1.html
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the GNU
// Lesser General Public License for more details.
//
// Contributors:
//     <NAME><<EMAIL>>
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TechF.Utilities;

namespace TechF.Test
{
    public class DictionaryComparisonTests
    {
        [Test]
        public void TestSameDictionariesAreEqual()
        {
            var d = new Dictionary<string, string>();
            Assert.IsTrue(DictionaryComparison<string, string>.Compare(d, d));
        }
        [Test]
        public void TestIdenticalDictionariesAreEqual()
        {
            var d1 = new Dictionary<string, string>();
            var d2 = new Dictionary<string, string>();
            d1.Add("test", "test");
            d2.Add("test", "test");
            Assert.IsTrue(DictionaryComparison<string, string>.Compare(d1, d2));
        }
        [Test]
        public void TestIdenticalKeysDifferentValuesAreNotEqual()
        {
            var d1 = new Dictionary<string, string>();
            var d2 = new Dictionary<string, string>();
            d1.Add("test", null);
            d2.Add("test", "test2");
            Assert.IsFalse(DictionaryComparison<string, string>.Compare(d1, d2));
        }
        [Test]
        public void TestDifferentKeysAreNotEqual()
        {
            var d1 = new Dictionary<string, string>();
            var d2 = new Dictionary<string, string>();
            d1.Add("test", "test2");
            d2.Add("test2", "test2");
            Assert.IsFalse(DictionaryComparison<string, string>.Compare(d1, d2));
        }
        [Test]
        public void TestDifferentNumberOfKeysAreNotEqual()
        {
            var d1 = new Dictionary<string, string>();
            var d2 = new Dictionary<string, string>();
            d1.Add("test", "test2");
            d2.Add("test", "test2");
            d1.Add("test1", "test2");
            Assert.IsFalse(DictionaryComparison<string, string>.Compare(d1, d2));
        }
    }
}
<file_sep>﻿// Tech-F Framework
// (C) Copyright 2014 <NAME><<EMAIL>>
//
// All rights reserved.This program and the accompanying materials
// are made available under the terms of the GNU Lesser General Public License
// (LGPL) version 2.1 which accompanies this distribution, and is available at
// http://www.gnu.org/licenses/lgpl-2.1.html
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the GNU
// Lesser General Public License for more details.
//
// Contributors:
//     <NAME><<EMAIL>>
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using TechF.CodeGeneration;

namespace TechF
{
    public class ClassFactoryOptions
    {
        internal ClassFactoryOptions(ClassFactoryBinder binder)
        {
            _binder = new WeakReference<ClassFactoryBinder>(binder);
        }
        private WeakReference<ClassFactoryBinder> _binder;

        public bool Persist
        {
            set
            {
                ClassFactoryBinder binder = null;
                if (_binder.TryGetTarget(out binder))
                {
                    binder._optionsLock.AcquireWriterLock(-1);
                    binder._persist = value;
                    binder._optionsLock.ReleaseWriterLock();
                }
            }
        }
        public bool BindProperties
        {
            set
            {
                ClassFactoryBinder binder = null;
                if (_binder.TryGetTarget(out binder))
                {
                    binder._optionsLock.AcquireWriterLock(-1);
                    binder._bindProperties = value;
                    binder._optionsLock.ReleaseWriterLock();
                }
            }
        }
    }
    public class ClassFactoryBinder
    {
        internal ClassFactoryBinder(ClassFactoryContext context, ClassFactoryBinder binder)
        {
            _context = context;
            _type = binder._type;
            _ctorCall = binder._ctorCall;
            _properties = binder._properties;
            _options = new ClassFactoryOptions(this);
            _persist = binder._persist;
            _lastBuild = new WeakReference(null);
        }
        internal ClassFactoryBinder(ClassFactoryContext context, Type type, ImmutableDictionary<string, string> properties)
        {
            _context = context;
            _type = type;
            _properties = properties;
            _options = new ClassFactoryOptions(this);
            _lastBuild = new WeakReference(null);
        }

        internal ClassFactoryContext _context;
        internal Type _type;
        internal Func<ClassFactoryBinder, object> _build;
        internal WeakReference _lastBuild = null;

        internal ImmutableDictionary<string, string> _properties;

        internal bool _persist;
        internal bool _bindProperties = true;
        internal ClassFactoryOptions _options;
        internal ReaderWriterLock _optionsLock = new ReaderWriterLock();

        internal ClassFactoryCodeGenerator.ConstructorCall _ctorCall = null;
        internal ClassFactoryCodeGenerator.PropertyBinder _propBinder = null;

        internal void Bind(object obj)
        {
            if (_propBinder == null)
            {
                var cachedCode = ClassFactoryCodeGenerator.GetCachedItem(_type, _properties);
                _propBinder = cachedCode.PropertyBinder;
            }

            _propBinder(obj);
        }

        internal object Create()
        {
            if (_ctorCall == null)
                _ctorCall = ClassFactoryCodeGenerator.GetCachedItem(_type, _properties).ConstructorCall;

            var persist = false;
            var propertyBind = false;
            _optionsLock.AcquireReaderLock(-1);
            persist = _persist;
            propertyBind = _bindProperties;
            _optionsLock.ReleaseReaderLock();

            if (_context == null)
            {
                // Do not persist in global scope
                var o = _ctorCall(null);
                if (propertyBind)
                    Bind(o);
                return _ctorCall(null);
            }
            var lastBuild = _lastBuild.Target;
            if (lastBuild != null && _lastBuild.IsAlive && persist)
                return lastBuild;

            lastBuild = _ctorCall(_context);
            if (propertyBind)
                Bind(lastBuild);
            _lastBuild.Target = lastBuild;

            return lastBuild;
        }
    }
}
