C# 简单的依赖解析器

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15715978/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 17:43:02  来源:igfitidea点击:

Simple Dependency Resolver

c#design-patternsdependency-injection

提问by Billa

How do you create simple Dependency Resolver, with out using any built in or library such as Autofac, Ninject, etc.

你如何创建简单的依赖解析器,而不使用任何内置或库,如 Autofac、Ninject 等。

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?

我做什么更好的代码并为构造函数参数提供其他对象实例?

回答by Christian Specht

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

已经有几年了,但是 Ayende 曾经写过一篇关于这个的博文:
用 15 行代码构建一个 IoC 容器

But this is only the very simplest possible implementation.
Ayende himself stated in his next postthat 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 completeIoC container is everything but trivial.

但这只是最简单的可能实现。
Ayende 本人在他的下一篇文章中表示,现有的 IoC 容器可以做更多的事情,而不仅仅是返回类实例——这就是它变得复杂的地方。
正如“相信我 - 我是一名医生”在他的评论中已经说过的那样:实现一个完整的IoC 容器绝非易事。

回答by Steven

You can write a container in just a few lines of code. At its core it would typically be a dictionary that with System.Typeas 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 Registermethods, both a generic and non-generic GetInstancemethod and allows auto-wiring:

您只需几行代码即可编写一个容器。它的核心通常是一个字典,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);
    }
}

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.

请注意,您永远不应该实际使用此类实现。它缺少 DI 库为您提供的许多重要功能,但与使用纯 DI(即手动连接对象图)相比没有任何优势。您失去了编译时支持,而没有得到任何回报。

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 Rootbecomes cumbersome, you could consider switching to one of the established DI libraries.

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

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.
  • 批量注册(一行注册一组类型)
  • 为一系列类型应用装饰器或拦截器
  • 将开放的泛型抽象映射到开放的泛型实现
  • 与常用应用平台(如ASP.NET MVC、Web API等)集成
  • 使用自定义生活方式注册类型。
  • 体面的错误报告(例如,而不是抛出堆栈溢出异常)
  • 用于验证配置正确性(以补偿编译时支持的损失)和诊断常见配置错误的工具。
  • 很棒的表演。

These features allow you to keep your DI configuration maintainable.

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