/// <summary>
        /// Add the ability to resolve an instance of <typeparam name="T"></typeparam>
        /// Without adding a resolver the bus will attempt to find and call the default
        /// constructor to create an instance when adding handlers from assemblies.
        /// Use <see cref="AddResolver{T}"/> if your handler does not have default constructor
        /// or you want to re-use an instance.
        /// </summary>
        /// <example>
        /// <code>
        /// // For type MessageHandler, call the c'tor that takes an IBus parameter
        /// bus.AddResolver(()=> new MessageHandler(bus));
        /// // find all the handlers in assemblies named *handlers.dll" in the current directory in the namespace
        /// "MyCorp.MessageHandlers
        /// bus.AddHandlersAndTranslators(Directory.GetCurrentDirectory(), "*handlers.dll", "MyCorp.MessageHandlers");
        /// </code>
        /// </example>
        /// <typeparam name="T">The type of instance to resolve.  Typically of type IConsumer{TMessage}</typeparam>
        /// <param name="bus">The <seealso cref="IBus"/> instance this will apply to</param>
        /// <param name="resolver">A delegate that returns an instance of <typeparamref name="T"/></param>
        public static void AddResolver <T>(this Patterns.Bus bus, Func <T> resolver)
        {
            if (!busResolverDictionaries.ContainsKey(bus))
            {
                busResolverDictionaries.Add(bus, new Dictionary <Type, Delegate>());
            }
            var dictionary = busResolverDictionaries[bus];

            dictionary[typeof(T)] = resolver;
        }
 public static void SetServiceLocator(this Patterns.Bus bus, IServiceLocator serviceLocator)
 {
     if (bus == null)
     {
         throw new ArgumentNullException(nameof(bus));
     }
     if (serviceLocator == null)
     {
         throw new ArgumentNullException(nameof(serviceLocator));
     }
     if (!busServiceLocators.ContainsKey(bus))
     {
         busServiceLocators.Add(bus, serviceLocator);
     }
     else
     {
         busServiceLocators[bus] = serviceLocator;
     }
 }
        /// <summary>
        /// Dynamically load message handlers by filename in a specific directory.
        /// </summary>
        /// <example>
        /// <code>
        /// // find all the handlers in assemblies named *handlers.dll" in the current directory in the namespace
        /// "MyCorp.MessageHandlers
        /// bus.AddHandlersAndTranslators(Directory.GetCurrentDirectory(), "*handlers.dll", "MyCorp.MessageHandlers");
        /// </code>
        /// </example>
        /// <param name="bus">The <seealso cref="IBus"/> instance this will apply to</param>
        /// <param name="directory">What directory to search</param>
        /// <param name="wildcard">What filenames to search</param>
        /// <param name="namespace">Include IConsumers{TMessage} within this namespace</param>
        public static void AddHandlersAndTranslators(this Patterns.Bus bus, string directory, string wildcard, string @namespace)
        {
            if (!busResolverDictionaries.ContainsKey(bus))
            {
                busResolverDictionaries.Add(bus, new Dictionary <Type, Delegate>());
            }
            IServiceLocator serviceLocator = busServiceLocators.ContainsKey(bus) ? busServiceLocators[bus] : new ActivatorServiceLocator();

            IEnumerable <Type> consumerTypes = typeof(IConsumer <>).ByImplementedInterfaceInDirectory(directory, wildcard, @namespace);

            foreach (var consumerType in consumerTypes)
            {
                var pipeImplementationInterface =
                    consumerType.GetInterfaces()
                    .FirstOrDefault(t => !t.IsGenericTypeDefinition && t.GetGenericTypeDefinition() == typeof(IPipe <,>));
                if (pipeImplementationInterface != null)
                {
                    var translatorType = consumerType;
                    var messageTypes   = pipeImplementationInterface.GetGenericTypeArguments();

                    // get instance of pipe
                    var translatorInstance = busResolverDictionaries[bus].ContainsKey(translatorType)
                                                ? InvokeFunc(busResolverDictionaries[bus][translatorType])
                                                : serviceLocator.GetInstance(translatorType);

                    // get instance of the helper that will help add specific handler
                    // code to the bus.
                    var helperType1              = typeof(PipeAttachConsumerHelper <,>).MakeGenericType(messageTypes);
                    var helperType1Instance      = Activator.CreateInstance(helperType1);
                    var attachConsumerMethodInfo = helperType1.GetMethod("AttachConsumer");
                    attachConsumerMethodInfo.Invoke(helperType1Instance, new[] { translatorInstance, bus });

                    var inType               = messageTypes[0];
                    var helperType           = typeof(BusAddhHandlerHelper <>).MakeGenericType(inType);
                    var helperInstance       = Activator.CreateInstance(helperType);
                    var addHandlerMethodInfo = helperType.GetMethod("AddHandler");

                    addHandlerMethodInfo.Invoke(helperInstance, new[] { bus, translatorInstance });
                }
                else
                {
                    var consumerImplementationInterface =
                        consumerType.GetInterfaces()
                        .FirstOrDefault(t => !t.IsGenericTypeDefinition && t.GetGenericTypeDefinition() == typeof(IConsumer <>));
                    Debug.Assert(consumerImplementationInterface != null,
                                 "Unexpected state enumerating implementations of IConsumer<T>");

                    var messageTypes = consumerImplementationInterface.GetGenericTypeArguments();

                    var helperType           = typeof(BusAddhHandlerHelper <>).MakeGenericType(messageTypes);
                    var helperInstance       = Activator.CreateInstance(helperType);
                    var addHandlerMethodInfo = helperType.GetMethod("AddHandler");

                    var handlerInstance = busResolverDictionaries[bus].ContainsKey(consumerType)
                                                ? InvokeFunc(busResolverDictionaries[bus][consumerType])
                                                : serviceLocator.GetInstance(consumerType);

                    addHandlerMethodInfo.Invoke(helperInstance, new[] { bus, handlerInstance });
                }
            }
        }