Simple Dependency Resolver
How do you create simple Dependency Resolver, with out using any built in or library such as Autofac, Ninject, etc.
This was my interview question.
I wrote this simple code and they said it does not look good. Its like very hard coded idea.
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);
}
}
What better code i do and supply other object instance for constructor parameter?
You can write a container in just a few lines of code. At its core it would typically be a dictionary that with System.Type
as its key and the value would be some object that allows you to create new instances of that type. When you write a simple implementation System.Func<object>
would do. Here is a simple implementation that contains several Register
methods, both a generic and non-generic GetInstance
method and allows auto-wiring:
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);
}
}
You can use it as follows:
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));
WARNING :
Please note that you should never actually use such implementation. It lacks many important features that DI libraries give you, yet gives no advantage over using Pure DI (ie hand-wiring object graphs). You loose compile-time support, without getting anything back.
When your application is small, you should start with Pure DI and once your application and your DI configuration grow to the point that maintaining you Composition Root becomes cumbersome, you could consider switching to one of the established DI libraries.
Here are some of the features that this naive implementation lacks compared to the established libraries:
These features allow you to keep your DI configuration maintainable.
It's already a few years old, but Ayende once wrote a blog post about this:
Building an IoC container in 15 lines of code
But this is only the very simplest possible implementation.
Ayende himself stated in his next post that the existing IoC containers can do much more stuff than just returning class instances - and this is where it gets complicated.
As "Trust me - I'm a Doctor" already said in his comment: implementing a complete IoC container is everything but trivial.
上一篇: 在Asp.Net Mvc 6中,public Boolean isAdmin
下一篇: 简单的依赖关系解析器