我有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()
});
或者是否有可能以某种方式自动注入它们?
肯定是的,你可以通过IoC容器注入它。但是,这取决于您的需求。如果您的Generator
太复杂并且需要大量参考,您可以使用IoC(e.x.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";
}
}
您可以从Assembly中反映它们,然后通过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的所有类,如果您创建一个新类,则无需手动添加它们。
您可以使用以下方法生成列表。
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
将确保未列出抽象类。
您可以使用reflection来实现此目的。
private static readonly List<TopicGenerator> generators =
Assembly.GetExecutingAssembly().GetTypes()
.Where(x => x.ImplementedInterfaces.Contains(typeof(TopicGenerator)))
.Select(x => (TopicGenerator)Activator.CreateInstance(x))
.ToList();