CodePaste Logo
New Snippet New Snippet Recent Snippets Recent Snippets My Snippets My Snippets Web Code Search Snippets Search
Sign inor Register
Language: C#

Generic catalog implementation along with acceptance test

873 Views
Copy Code Show/Hide Line Numbers
    public class GenericCatalog : ComposablePartCatalog, INotifyComposablePartCatalogChanged
    {
        private ComposablePartCatalog _decoratedCatalog;
        private AggregateCatalog _catalog = new AggregateCatalog();
        private IDictionary<string, Type> _closedTypes = new Dictionary<string, Type>();
        private IDictionary<string, Type> _genericTypes = new Dictionary<string, Type>();
 
        public GenericCatalog(ComposablePartCatalog catalog)
        {
            _decoratedCatalog = catalog;
            _catalog.Catalogs.Add(_decoratedCatalog);
            _catalog.Changing += (s, e) => { OnChanging(e); };
            InitializeLocators();
        }
 
        private void InitializeLocators()
        {
            using (var ep = new CatalogExportProvider(_decoratedCatalog))
            {
                ep.SourceProvider = ep;
                var locatorExports = ep.GetExports<TypeLocator, ITypeLocatorView>();
                foreach (var export in locatorExports)
                {
                    var locator = export.Value;
                    _genericTypes.Add(export.Metadata.FullName, locator.Type);
                }
            }
        }
 
        private void OnChanging(ComposablePartCatalogChangeEventArgs e)
        {
            var handler = Changing;
            if (handler != null)
                handler(this, e);
        }
 
        public override IQueryable<ComposablePartDefinition> Parts
        {
            get { return _catalog.Parts; }
        }
 
        public override IEnumerable<Tuple<ComposablePartDefinition, ExportDefinition>> GetExports(ImportDefinition definition)
        {
            Type importDefinitionType = null;
            var exports = _catalog.GetExports(definition);
            if (!exports.Any()) {
                var contractDef = definition as ContractBasedImportDefinition;
                if (contractDef != null && !definition.GetType().BaseType.Equals(typeof(ImportDefinition)))
                {
                    importDefinitionType = GetImportDefinitionType(definition);
                    if (ShouldCreateClosedGenericPart(contractDef, importDefinitionType))
                    {
                        CreateGenericPart(importDefinitionType);
                        exports = _catalog.GetExports(definition);
                    }
                }
            }
            return exports;
        }
 
        private void CreateGenericPart(Type importDefinitionType)
        {
            var type = BuildGenericType(importDefinitionType);
            var typeCatalog = new TypeCatalog(type);
            _catalog.Catalogs.Add(typeCatalog);
            _closedTypes.Add(importDefinitionType.FullName,type);
        }
 
        private bool ShouldCreateClosedGenericPart(ContractBasedImportDefinition contractDef, Type importDefinitionType)
        {
            return contractDef.Cardinality != ImportCardinality.ZeroOrMore && importDefinitionType.IsGenericType && 
                   !_closedTypes.ContainsKey(importDefinitionType.FullName);
        }
 
        private Type GetImportDefinitionType(ImportDefinition definition)
        {
            Type importDefinitionType = null;
            if (ReflectionModelServices.IsImportingParameter(definition))
                importDefinitionType = GetParameterType(definition);
            else
                importDefinitionType = GetMethodType(definition, importDefinitionType);
            return importDefinitionType;
        }
 
        private Type GetMethodType(ImportDefinition definition, Type importDefinitionType)
        {
            var memberInfos = ReflectionModelServices.GetImportingMember(definition).GetAccessors();
            var memberInfo = memberInfos[0];
 
            if (memberInfo.MemberType == MemberTypes.Method)
            {
                var methodInfo = (MethodInfo) memberInfo;
                importDefinitionType = methodInfo.ReturnType;
            }
            else if (memberInfo.MemberType == MemberTypes.Field)
            {
                var fieldInfo = (FieldInfo) memberInfo;
                importDefinitionType = fieldInfo.FieldType;
            }
            return importDefinitionType;
        }
 
        private Type GetParameterType(ImportDefinition definition)
        {
            Type importDefinitionType;
            var importingParameter = ReflectionModelServices.GetImportingParameter(definition);
            var parameterInfo = importingParameter.Value;
            importDefinitionType = parameterInfo.ParameterType;
            return importDefinitionType;
        }
 
        private Type BuildGenericType(Type importDefinitionType)
        {
            var genericImportTypeDefinition = importDefinitionType.GetGenericTypeDefinition();
            var genericTypeLocator = _genericTypes[genericImportTypeDefinition.FullName];
            var genericType = genericTypeLocator.MakeGenericType(importDefinitionType.GetGenericArguments());
            return genericType;
        }
 
        public event EventHandler<ComposablePartCatalogChangeEventArgs> Changed;
        public event EventHandler<ComposablePartCatalogChangeEventArgs> Changing;
    }
 
// Type locator - used for exporting generic parts
 
    public abstract class TypeLocator
    {
        public TypeLocator()
        {
            
        }
 
        public abstract Type Type { get; }
    }
 
    [MetadataAttribute]
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false)]
    public class TypeLocatorAttribute : ExportAttribute
    {
        public TypeLocatorAttribute(Type type)
            : base(typeof(TypeLocator))
        {
            FullName = type.FullName;
        }
 
        public string FullName { get; private set; }
 
    }
 
    public interface ITypeLocatorView
    {
        string FullName { get; }
    }
 
// Test, illustrates importing an IRespository<Order> from an Repository<> Type locator.
 
    [TestClass]
    public class GenericCatalogFixture
    {
 
        [TestMethod]
        public void When_IRepository_Customer_is_resolved_it_is_created_by_catalog()
        {
            var typeCatalog = new TypeCatalog(typeof(OrderProcessor), typeof(RepositoryTypeLocator),typeof(Logger));
            var catalog = new GenericCatalog(typeCatalog);
            var container = new CompositionContainer(catalog);
            var orderProcessor = container.GetExportedValue<OrderProcessor>();
            Assert.IsNotNull(orderProcessor.OrderRepository);
        }
    }
 
    public class Order
    {
        
    }
 
    [TypeLocator(typeof(IRepository<>))]
    public class RepositoryTypeLocator : TypeLocator
    {
        public override Type Type
        {
            get { return typeof (Repository<>); }
        }
    }
    
    [Export]
    public class OrderProcessor
    {
        [Import]
        public IRepository<Order> OrderRepository { get; set; }
    }
 
    public class Repository<T> : IRepository<T>
    {
        [Import]
        public ILogger Logger { get; set; }
    }
 
    [InheritedExport]
    public interface IRepository<T>
    {
    }
 
    public class Logger : ILogger
    {
    }
 
    [InheritedExport]
    public interface ILogger
    {
        
    }
by Glenn Block
  August 07, 2009 @ 12:31am
Tags:
Description:
GenericCatalog along with sample. Supports importing open generic types on a part. Requires implementing a derived TypeLocator for each open-generic part.

Add a comment


Report Abuse
brought to you by:
West Wind Techologies



If you find this site useful and use it frequently please consider making a donation to support this free service.
Donate