Получить список всех реализованных интерфейсов - PullRequest
0 голосов
/ 04 марта 2019

У меня есть 3 класса с одинаковым интерфейсом:

cppTopicGenerator : TopicGenerator
phpTopicGenerator : TopicGenerator
javaTopicGenerator : TopicGenerator

И я создал для них фасад, где я пытаюсь использовать их, как показано ниже:

public class MyFacade 
{
    private readonly List<TopicGenerator> generators;

    public void BusinessLogic(string extension)
    {
            MyParser(extenstion).generate();
    }


    private TopicGenerator MyParser(string extension)
    {
        foreach (var generator in generators)
        {
            if (generator.Accept(extension))
            {
                return generator;
            }
        }
        throw new NotFoundException($"Generator for {extension} doesnt exist.");
    }
}

вопросэто, как должен был создать этот список генератора?Мне нужно вручную создать список всех генераторов, например:

private readonly List<TopicGenerator> generators = new List(
        {
            new CppTopicGenerator()
            new PhpTopicGenerator()
            new JavaTopicGenerator()
        });

Или возможно их как-то автоматически внедрить?

Ответы [ 4 ]

0 голосов
/ 04 марта 2019

Вы можете сгенерировать список, используя следующее.

var list = AppDomain.CurrentDomain.GetAssemblies()
                    .SelectMany(x => x.GetTypes())
                    .Where(p => typeof(TopicGenerator).IsAssignableFrom(p) && p.IsClass && !p.IsAbstract)
                    .Select(x => (TopicGenerator)Activator.CreateInstance(x)).ToList<TopicGenerator>();

Что он делает, он отображает и повторяет типы в сборке и проверяет, реализован ли конкретный интерфейс.!p.IsAbstract гарантирует, что абстрактные классы не перечислены.

0 голосов
/ 04 марта 2019

Вы можете отразить их из сборки и затем создать их экземпляр с помощью Activator:

    public MyFacade() {
        //Reflect them
        var type = typeof(TopicGenerator);
        var types = AppDomain.CurrentDomain.GetAssemblies()
        .SelectMany(s => s.GetTypes())
        .Where(p => type.IsAssignableFrom(p) && !p.IsInterface);
        //Instantiate them
        generators = types.Select(t => Activator.CreateInstance(t) as TopicGenerator).ToList();
    }

, таким образом, вы найдете все классы, которые реализуют TopicGenerator, и вам не нужно добавлять их вручную, если вы создаете новыйодин.

0 голосов
/ 04 марта 2019

Вы можете использовать отражение для достижения этой цели.

private static readonly List<TopicGenerator> generators = 
    Assembly.GetExecutingAssembly().GetTypes()
        .Where(x => x.ImplementedInterfaces.Contains(typeof(TopicGenerator)))
        .Select(x => (TopicGenerator)Activator.CreateInstance(x))
        .ToList();
0 голосов
/ 04 марта 2019

Определенно, да, вы можете добавить его через контейнеры IoC.Но это зависит от ваших потребностей.Если ваш Generator слишком сложный и требует много ссылок, вы можете использовать IoC (например, Autofac ), но если он облегченный, я предпочитаю создавать его вручную.

Примеры (Все примеры в консолиприложение): 1) Вручную

using System;
using System.Collections.Generic;

namespace Test
{
    class MainClass
    {
        public static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");

            var service = new MyFacade();

            service.MyParser("foo");
            service.MyParser("bar");
            service.MyParser("foobar");
        }
    }

    public class MyFacade
    {
        private readonly IEnumerable<IGenerator> _generators;

        public MyFacade()
        {
            _generators = new List<IGenerator>()
            {
                new CppTopicGenerator(),
                new PhpTopicGenerator(),
                new JavaTopicGenerator(),
            };
        }

        public IGenerator MyParser(string extension)
        {
            foreach (var generator in _generators)
            {
                if (generator.Accept(extension))
                {
                    return generator;
                }
            }

            throw new NotFoundException($"Generator for {extension} doesnt exist.");
        }
    }

    public interface IGenerator
    {
        bool Accept(string extension);
    }

    public class CppTopicGenerator : IGenerator
    {
        public bool Accept(string extension)
        {
            Console.WriteLine("CppTopicGenerator checking executed");
            return extension == "foo";
        }
    }

    public class PhpTopicGenerator : IGenerator
    {
        public bool Accept(string extension)
        {
            Console.WriteLine("PhpTopicGenerator checking executed");
            return extension == "bar";
        }
    }

    public class JavaTopicGenerator : IGenerator
    {
        public bool Accept(string extension)
        {
            Console.WriteLine("JavaTopicGenerator checking executed");
            return extension == "foobar";
        }
    }
}

2) Autofac:

class MainClass
    {
        public static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");

            var builder = new ContainerBuilder();

            builder.RegisterAssemblyTypes(AppDomain.CurrentDomain.GetAssemblies()).As<IGenerator>();
            builder.RegisterType<MyFacade>();

            var container = builder.Build();

            using (var scope = container.BeginLifetimeScope())
            {
                var service = scope.Resolve<MyFacade>();

                service.MyParser("foo");
                service.MyParser("bar");
                service.MyParser("foobar");
            }
        }
    }

    public class MyFacade
    {
        private readonly IEnumerable<IGenerator> _generators;

        public MyFacade(IEnumerable<IGenerator> generators)
        {
            _generators = generators;
        }

        public IGenerator MyParser(string extension)
        {
            foreach (var generator in _generators)
            {
                if (generator.Accept(extension))
                {
                    return generator;
                }
            }

            throw new NotFoundException($"Generator for {extension} doesnt exist.");
        }
    }

    public interface IGenerator
    {
        bool Accept(string extension);
    }

    public class CppTopicGenerator : IGenerator
    {
        public bool Accept(string extension)
        {
            Console.WriteLine("CppTopicGenerator checking executed");
            return extension == "foo";
        }
    }

    public class PhpTopicGenerator : IGenerator
    {
        public bool Accept(string extension)
        {
            Console.WriteLine("PhpTopicGenerator checking executed");
            return extension == "bar";
        }
    }

    public class JavaTopicGenerator : IGenerator
    {
        public bool Accept(string extension)
        {
            Console.WriteLine("JavaTopicGenerator checking executed");
            return extension == "foobar";
        }
    }
...