简单的依赖关系解析器
如何创建简单的依赖关系解析器,无需使用任何内置或库,如Autofac,Ninject等。
这是我的面试问题。
我写了这个简单的代码,他们说这看起来不太好。 它像非常硬编码的想法。
public interface IRepository { }
interface IDataProvider
{
List<string> GetData();
}
public class SQLDataProvider : IDataProvider
{
private readonly IRepository _repository { get; set; }
public SQLDataProvider(IRepository repository)
{
_repository = repository;
}
public List<string> GetData()
{
return new List<string> { "" };
}
}
public class MockDataProvider : IDataProvider
{
public List<string> GetData()
{
return new List<string> { "" };
}
}
class Program
{
static void Main(string[] args)
{
string targetClass = "SQLDataProvider";
//Here i need to supply IRepository instance too
IDataProvider dataProvider =
(IDataProvider)Activator.CreateInstance(typeof(IDataProvider), targetClass);
}
}
我做了哪些更好的代码并为构造函数参数提供其他对象实例?
只需几行代码即可编写容器。 在其核心,它通常是一个以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:logslog.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(即手持连线对象图)相比,却没有优势。 你松散的编译时支持,没有得到任何回报。
当您的应用程序很小时,您应该从Pure DI开始,一旦您的应用程序和DI配置增长到维护组合根变得麻烦的程度,您可以考虑切换到其中一个已建立的DI库。
以下是这个天真的实现与已建立的库相比所缺少的一些功能:
这些功能可让您保持DI配置的可维护性。
它已经有几年了,但Ayende曾经写过一篇关于这个的博客文章:
用15行代码构建一个IoC容器
但这只是最简单的实现。
Ayende在他的下一篇文章中指出,现有的IoC容器可以做更多的事情,而不仅仅是返回类实例 - 而这正是它变得复杂的地方。
正如“相信我 - 我是医生”在他的评论中已经说过的那样:实施一个完整的IoC容器不过是微不足道的。
上一篇: Simple Dependency Resolver
下一篇: Dependency Injection prevent dependency on the dependency container