Reputation: 1621
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
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
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
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
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