只需几行代码即可编写容器。在它的核心,它通常是一个以System.Type
为关键字的字典,其价值将是允许您创建该类型的新实例的某个对象。当你写一个简单的实现System.Func<object>
会做。下面是一个包含若干Register
方法,同时包含通用和非通用GetInstance
方法,并允许自动装配一个简单的实现:
public class Container
{
Dictionary<Type, Func<object>> registrations = new Dictionary<Type, Func<object>>();
public void Register<TService, TImpl>() where TImpl : TService {
this.registrations.Add(typeof(TService),() => this.GetInstance(typeof(TImpl)));
}
public void Register<TService>(Func<TService> instanceCreator) {
this.registrations.Add(typeof(TService),() => instanceCreator());
}
public void RegisterSingleton<TService>(TService instance) {
this.registrations.Add(typeof(TService),() => instance);
}
public void RegisterSingleton<TService>(Func<TService> instanceCreator) {
var lazy = new Lazy<TService>(instanceCreator);
this.Register<TService>(() => lazy.Value);
}
public object GetInstance(Type serviceType) {
Func<object> creator;
if (this.registrations.TryGetValue(serviceType, out creator)) return creator();
else if (!serviceType.IsAbstract) return this.CreateInstance(serviceType);
else throw new InvalidOperationException("No registration for " + serviceType);
}
private object CreateInstance(Type implementationType) {
var ctor = implementationType.GetConstructors().Single();
var parameterTypes = ctor.GetParameters().Select(p => p.ParameterType);
var dependencies = parameterTypes.Select(t => this.GetInstance(t)).ToArray();
return Activator.CreateInstance(implementationType, dependencies);
}
}
可以按如下方式使用它:
var container = new Container();
container.RegisterSingleton<ILogger>(new FileLogger("c:\\logs\\log.txt"));
// SqlUserRepository depends on ILogger
container.Register<IUserRepository, SqlUserRepository>();
// HomeController depends on IUserRepository
// Concrete instances don't need to be resolved
container.GetInstance(typeof(HomeController));
警告 :
请注意,你不应该实际使用这种实现。它缺少DI库提供的许多重要功能,但与使用Pure DI(即手工连接的对象图)相比没有优势。你松散的编译时支持,没有得到任何回报。
当你的应用程序是小,你应该用纯DI一旦你的应用程序和DI配置成长到维护您Composition Root变得麻烦,你可以考虑切换到建立DI库的一个点开始。
下面是一些,这幼稚实施缺乏相比建立库的特征:
- 批量注册(注册一组类型与单个线)
- 应用装饰或拦截器为一系列的类型
- 映射开放通用抽象打开通用实现
- 集成公共应用平台(如ASP.NET MVC,网络API等)
- 注册具有自定义生活方式的类型。
- 正确的错误报告(而不是抛出堆栈溢出例外)
- 验证配置的正确性(以补偿编译时支持的损失)和诊断常见配置错误的工具。
- 良好的表现。
这些功能可让您保持DI配置的可维护性。
大多数IoC容器都是开源的,例如, [SimpleInjector](http://simpleinjector.codeplex.com/)和[Autofac](http://code.google.com/p/autofac/source/browse/),因此您可以窥探灵感。警告字 - 实现*不是微不足道的。 –
在一个侧面说明,这是一个令人难以置信的弱智面试问题。 – Filip
这个问题似乎是脱离主题,因为它基本上是要求代码审查。它属于“代码评审”。 –