degath
degath

Reputation: 1621

Get list of all implemented interfaces

I've got 3 classes with the same interface:

cppTopicGenerator : TopicGenerator
phpTopicGenerator : TopicGenerator
javaTopicGenerator : TopicGenerator

And I created a facade for them where I try to use them as below:

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.");
    }
}

the question is, how should've created this Generator list? I need to create manually the list of all generators like:

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

Or is it possible to inject them somehow automatically?

Upvotes: 1

Views: 369

Answers (4)

Yauhen Sampir
Yauhen Sampir

Reputation: 2104

Definitely yes, you can inject it via IoC containers. But, it depends on your needs. If your Generator too complicated and need lots of references you can use IoC(e.x. Autofac), but if it lightweight I prefer to create it manually.

Examples(All examples in console application): 1) Manually

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";
        }
    }

Upvotes: 2

Creyke
Creyke

Reputation: 2107

You can use reflection to achieve this.

private static readonly List<TopicGenerator> generators = 
    Assembly.GetExecutingAssembly().GetTypes()
        .Where(x => x.ImplementedInterfaces.Contains(typeof(TopicGenerator)))
        .Select(x => (TopicGenerator)Activator.CreateInstance(x))
        .ToList();

Upvotes: 1

Anu Viswan
Anu Viswan

Reputation: 18155

You could generate the list using following.

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>();

What it does is, it reflects and iterates over the types in assembly and check if particular interface is implemented. The !p.IsAbstract would ensure abstract classes are not listed.

Upvotes: 1

MarcoFernandezHeras
MarcoFernandezHeras

Reputation: 21

You can reflect them from the Assembly and then Instantiate them via 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();
    }

this way you'll find all classes that implement TopicGenerator and you wont need to add them manually if you create a new one.

Upvotes: 1

Related Questions