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

A conventional catalog for MEF (Prototype)

2526 Views
Copy Code Show/Hide Line Numbers
using System;
using System.ComponentModel.Composition.Primitives;
using System.Collections.Generic;
using System.ComponentModel.Composition.ReflectionModel;
using System.ComponentModel.Composition;
using System.Reflection;
using System.Linq;
using System.ComponentModel.Composition.Hosting;
using System.Collections;
 
namespace Microsot.ComponentModel.Composition
{
    public class ConventionalCatalog : ComposablePartCatalog
    {
        private List<ComposablePartDefinition> _parts = new List<ComposablePartDefinition>();
 
        public void RegisterType<TImplementation, TContract>()
        {
            var part = ReflectionModelServices.CreatePartDefinition(
                new Lazy<Type>(() => typeof(TImplementation)),
                false,
                new Lazy<IEnumerable<ImportDefinition>>(() => GetImportDefinitions(typeof(TImplementation))),
                new Lazy<IEnumerable<ExportDefinition>>(() => GetExportDefinitions(typeof(TImplementation), typeof(TContract))),
                new Lazy<IDictionary<string, object>>(() => new Dictionary<string, object>()),
                null);
 
            this._parts.Add(part);
        }
 
        private ImportDefinition[] GetImportDefinitions(Type implementationType)
        {
            var constructors = implementationType.GetConstructors()[0];
            var imports = new List<ImportDefinition>();
 
            foreach (var param in constructors.GetParameters())
            {
                var cardinality = GetCardinality(param);
                var importType = cardinality == ImportCardinality.ZeroOrMore ? GetCollectionContractType(param.ParameterType) : param.ParameterType;
 
                imports.Add(
                    ReflectionModelServices.CreateImportDefinition(
                        new Lazy<ParameterInfo>(() => param),
                        AttributedModelServices.GetContractName(importType),
                        AttributedModelServices.GetTypeIdentity(importType),
                        Enumerable.Empty<KeyValuePair<string,Type>>(),
                        cardinality,
                        CreationPolicy.Any,
                        null));
 
            }
            return imports.ToArray();
        }
 
        private ImportCardinality GetCardinality(ParameterInfo param)
        {
            if (typeof(IEnumerable).IsAssignableFrom(param.ParameterType))
                return ImportCardinality.ZeroOrMore;
            else
                return ImportCardinality.ExactlyOne;
        }
 
        //This is hacky! Needs to be cleaned up as it makes many assumptions.
        private Type GetCollectionContractType(Type collectionType)
        {
            var itemType = collectionType.GetGenericArguments().First();
            var contractType = itemType.GetGenericArguments().First();
            return contractType;
        }
 
        private ExportDefinition[] GetExportDefinitions(Type implementationType, Type contractType)
        {
            var lazyMember = new LazyMemberInfo(implementationType);
            var contracName = AttributedModelServices.GetContractName(contractType);
            var metadata = new Lazy<IDictionary<string, object>>(() =>
            {
                var md = new Dictionary<string, object>();
                md.Add(CompositionConstants.ExportTypeIdentityMetadataName, AttributedModelServices.GetTypeIdentity(contractType));
                return md;
            });
 
            return new ExportDefinition[] { ReflectionModelServices.CreateExportDefinition(lazyMember, contracName, metadata, null) };
        }
 
        public override IQueryable<ComposablePartDefinition> Parts
        {
            get
            {
                return this._parts.AsQueryable();
            }
        }
 
        public override IEnumerable<Tuple<ComposablePartDefinition, ExportDefinition>> GetExports(ImportDefinition definition)
        {
            return base.GetExports(definition);
        }
    }
 
}
 
//sample parts and contracts
 
public interface IRule { }
public interface IRulesEngine { }
public interface ILogger { }
 
public class Logger : ILogger {
}
 
public class Rule1 : IRule {
    private ILogger _logger;
 
    public Rule1(ILogger logger)
    {
        _logger = logger;
    }
}
 
public class Rule2 : IRule
{
    private ILogger _logger;
 
    public Rule2(ILogger logger)
    {
        _logger = logger;
    }
}
 
public class RulesEngine {
 
    private IEnumerable<Lazy<IRule>> _rules;
    
    public RulesEngine (IEnumerable<Lazy<IRule>> rules)
    {
        _rules = rules;
    }
}
 
//Sample
public class Test {
     public Test() {
          var catalog = new ConventionalCatalog();
          catalog.RegisterType<Rule1, IRule>();
          catalog.RegisterType<Rule2, IRule>();
          catalog.RegisterType<Logger, ILogger>();
          catalog.RegisterType<RulesEngine, RulesEngine>();
          var container = new CompositionContainer(catalog);
          var engine = container.GetExportedValue<RulesEngine>();
     }
}
 
by Glenn Block
  November 17, 2009 @ 1:26pm
Tags:
Description:
Prototype of a MEF POCO catalog. Uses our ReflectionModelServices api to configure through conventions. Supports Lazy as well.

Does not support export metadata (no way to define it), property injection, or recompostion.

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