简单依赖解决方案 [英] Simple Dependency Resolver

查看:106
本文介绍了简单依赖解决方案的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何创建简单的Dependency Resolver,使用任何内置的或AutoFac,Ninject等库。



这是我的面试问题。 p>

我写了这个简单的代码,他们说它看起来不太好。它像非常硬编码的想法。

  public interface IRepository {} 
接口IDataProvider
{
列表< string>的GetData();
}
public class SQLDataProvider:IDataProvider
{
private readonly IRepository _repository {get;组;
public SQLDataProvider(IRepository repository)
{
_repository = repository;
}
public List< string> GetData()
{
返回新列表< string> {};
}
}
public class MockDataProvider:IDataProvider
{
public List< string> GetData()
{
返回新列表< string> {};
}
}
类程序
{
static void Main(string [] args)
{
string targetClass =SQLDataProvider;
//这里我需要提供IRepository实例
IDataProvider dataProvider =
(IDataProvider)Activator.CreateInstance(typeof(IDataProvider),targetClass);

}
}

我做什么更好的代码

解决方案

你可以在几行代码中写一个容器。它的核心是通常使用 System.Type 作为键的字典,该值将是一些允许您创建该类型的新实例的对象。当你编写一个简单的实现 System.Func< object> 会做。这是一个简单的实现,包含几个注册方法,通用和非通用的 GetInstance 方法,接线:

  public class Container 
{
Dictionary< Type,Func< ;对象>> registrationrations = new Dictionary< Type,Func< object>>();

public void注册< TService,TImpl>()其中TImpl:TService {
this.registrations.Add(typeof(TService),()=> this.GetInstance(typeof(TImpl )));
}

public void注册< 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>创作者;
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);
}

私有对象CreateInstance(Type implementationType){
var ctor = implementationType.GetConstructors()。
var parameterTypes = ctor.GetParameters()。Select(p => p.ParameterType);
var dependencies = parameterTypes.Select(t => this.GetInstance(t))。ToArray();
返回Activator.CreateInstance(implementationType,dependencies);
}
}

您可以使用它如下:

  var container = new Container(); 

container.RegisterSingleton< ILogger>(新的FileLogger(c:\\\logs\\log.txt));

// SqlUserRepository取决于ILogger
container.Register< IUserRepository,SqlUserRepository>();

// HomeController依赖于IUserRepository
//具体实例不需要解析
container.GetInstance(typeof(HomeController));

警告



请注意,您绝对不应该使用此类实现。它没有很多重要的功能,DI图书馆给你,但没有优于使用纯DI (即手工布线对象图)。您松开了编译时的支持,没有任何回调。



当您的应用程序很小时,您应该从Pure DI开始,一旦您的应用程序和DI配置增长到维护您的组合根目录变得麻烦,您可以考虑切换到已建立的DI库之一。



以下是与已建立的库相比,这种天真的实现缺乏的一些功能:




  • 批量注册(用一行注册一组类型)

  • 应用一系列类型的装饰器或拦截器

  • 将打开的通用抽象映射到打开通用实现

  • 与通用应用程序平台(如ASP.NET MVC,Web API等)集成

  • 使用自定义的生活方式注册类型。

  • 体面的错误报告(i

  • 用于验证配置正确性(补偿编译时支持的丢失)和诊断常见配置错误的工具。

  • 良好的表现。



这些功能可让您保持DI配置的可维护性。


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:\\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));

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 (i.e. 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:

  • Batch registration (registering a set of types with a single line)
  • Applying decorators or interceptors for a range of types
  • Mapping open generic abstractions to open generic implementations
  • Integration with common application platforms (such as ASP.NET MVC, Web API, etc)
  • Registering types with custom lifestyles.
  • Decent error reporting (instead of throwing stack overflow exceptions for instance)
  • Tools for verifying the correctness of the configuration (to compensate the loss of compile-time support) and diagnosing common configuration mistakes.
  • Good performance.

These features allow you to keep your DI configuration maintainable.

这篇关于简单依赖解决方案的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆