dimanche 20 février 2022

error when invoking Activator.CreateInstance with IEnumerable parameter filtered with LINQ

tl;dr:
When I filter output of ServiceProvider.GetServices(Type) for some reason I cannot use it later for constructing object with reflection. What am I missing?

Complete console application with DependencyInjection as its only dependency:

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.DependencyInjection;

namespace GenericsExperiment
{
    class Program
    {
        static void Main(string[] args)
        {
            //setup DI
            var services = new ServiceCollection();
            services.AddTransient<ISomeHandler<Message>, MessageHandler>();
            services.AddTransient<ISomeHandler<Message>, MessageHandler2>();
            var serviceProvider = services.BuildServiceProvider();

            //get all types of ISomeHandler<Message>
            var messageType = typeof(Message);
            var handlerType = typeof(ISomeHandler<>);
            var handlerGenericType = handlerType.MakeGenericType(messageType);
            var handlers = serviceProvider.GetServices(handlerGenericType);

            //Create SomeService type and pass handlers to constructor
            var someServiceType = typeof(SomeService<>);
            var someServiceGenericType = someServiceType.MakeGenericType(messageType);
            var concreteService = Activator.CreateInstance(someServiceGenericType,
                handlers) as SomeService<Message>;
            Console.WriteLine("Concrete type with all handlers created");


            //same as above but this time use primitive filtering:
            var filteredHandlers = serviceProvider.GetServices(handlerGenericType)
                .Where(h => h.GetType().FullName.Contains("MessageHandler2")).ToList();

            //this line throws exception System.MissingMethodException: Constructor on type
            //'GenericsExperiment.SomeService`1[[GenericsExperiment.Message, GenericsExperiment,
            //Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]' not found.
            var concreteServiceWithFilteredHandlers = Activator.CreateInstance(someServiceGenericType,
                filteredHandlers) as SomeService<Message>;

        }
    }

    public class Message { public string Value { get; set; } }

    public interface ISomeHandler<in T> {
        void Handle(T message);
    }

    public class MessageHandler : ISomeHandler<Message> {
        public void Handle(Message message)=>Console.WriteLine($"handled: {message.Value}");
    }

    public class MessageHandler2 : ISomeHandler<Message> {
        public void Handle(Message message) => Console.WriteLine($"handled by messageHandler 2: {message.Value}");
    }

    public class SomeService<T> where T : class {
        public SomeService(IEnumerable<ISomeHandler<T>> handlers) { }

        public void DoSomethingWithHandlers() => throw new NotImplementedException();
    }
}




Aucun commentaire:

Enregistrer un commentaire