.NET 中的依赖注入示例?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/743951/
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-09-03 12:30:20  来源:igfitidea点击:

Dependency Injection in .NET with examples?

.netdependency-injection

提问by JohnIdol

Can someone explain dependency injectionwitha basic .NET exampleand provide a few links to .NET resources to extend on the subject?

有人可以一个基本的 .NET 示例解释依赖注入并提供一些指向 .NET 资源的链接以扩展该主题吗?

This is not a duplicate of What is dependency injection?because I am asking about specific .NET examples and resources.

这不是什么是依赖注入?因为我在询问特定的 .NET 示例和资源。

回答by

Here's a common example. You need to log in your application. But, at design time, you're not sure if the client wants to log to a database, files, or the event log.

这是一个常见的例子。您需要登录您的应用程序。但是,在设计时,您不确定客户端是要记录到数据库、文件还是事件日志。

So, you want to use DI to defer that choice to one that can be configured by the client.

因此,您希望使用 DI 将该选择推迟到可由客户端配置的选择。

This is some pseudocode (roughly based on Unity):

这是一些伪代码(大致基于 Unity):

You create a logging interface:

您创建一个日志记录界面:

public interface ILog
{
  void Log(string text);
}

then use this interface in your classes

然后在你的类中使用这个接口

public class SomeClass
{
  [Dependency]
  public ILog Log {get;set;}
}

inject those dependencies at runtime

在运行时注入这些依赖项

public class SomeClassFactory
{
  public SomeClass Create()
  {
    var result = new SomeClass();
    DependencyInjector.Inject(result);
    return result;
  }
}

and the instance is configured in app.config:

并且实例在 app.config 中配置:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name ="unity"
             type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,
              Microsoft.Practices.Unity.Configuration"/>
  </configSections>
  <unity>
    <typeAliases>
      <typeAlias alias="singleton"
                 type="Microsoft.Practices.Unity.ContainerControlledLifetimeManager,Microsoft.Practices.Unity" />
    </typeAliases>
    <containers>
      <container>
        <types>
          <type type="MyAssembly.ILog,MyAssembly"
                mapTo="MyImplementations.SqlLog, MyImplementations">
            <lifetime type="singleton"/>
          </type>
        </types>
      </container>
    </containers>
  </unity>
</configuration>

Now if you want to change the type of logger, you just go into the configuration and specify another type.

现在,如果您想更改记录器的类型,只需进入配置并指定另一种类型即可。

回答by Sam Saffron

Ninjectmust have one of the coolest sample out there: (pieced from the sample)

Ninject必须有最酷的样品之一:(从样品中拼凑而成)

interface IWeapon {
  void Hit(string target);
}
class Sword : IWeapon {
  public void Hit(string target) {
    Console.WriteLine("Chopped {0} clean in half", target);
  }
}
class Shuriken : IWeapon {
  public void Hit(string target) {
    Console.WriteLine("Shuriken tossed on {0}", target);
  }
}
class Samurai {
  private IWeapon _weapon;

  [Inject]
  public Samurai(IWeapon weapon) {
    _weapon = weapon;
  }

  public void Attack(string target) {
    _weapon.Hit(target);
  }
}

class WeaponsModule: NinjectModule {
  private readonly bool _useMeleeWeapons;

  public WeaponsModule(bool useMeleeWeapons) {
    _useMeleeWeapons = useMeleeWeapons;
  }

  public void Load() {
    if (useMeleeWeapons)
      Bind<IWeapon>().To<Sword>();
    else
      Bind<IWeapon>().To<Shuriken>();
  }
}

class Program {
  public static void Main() {
    bool useMeleeWeapons = false;
    IKernel kernel = new StandardKernel(new WeaponsModule(useMeleeWeapons));
    Samurai warrior = kernel.Get<Samurai>();
    warrior.Attack("the evildoers");
  }
}

This, to me, reads very fluently, before you start up your dojo you can decide how to arm your Samurais.

对我来说,这非常流畅,在您开始道场之前,您可以决定如何武装您的武士。

回答by Danny van der Kraan

I think it is important that you first learn DI without IoC Containers. So therefor I've written an example that slowly builts up to an IoC Container. It's a real example from my work, but still made basic enough for novices to grab the essence of DI. You can find it here: https://dannyvanderkraan.wordpress.com/2015/06/15/real-world-example-of-dependeny-injection/

我认为在没有 IoC Containers 的情况下首先学习 DI 很重要。因此,我编写了一个示例,该示例慢慢构建为 IoC 容器。这是我工作中的一个真实示例,但仍然足以让新手掌握 DI 的本质。你可以在这里找到它:https: //dannyvanderkraan.wordpress.com/2015/06/15/real-world-example-of-dependeny-injection/

It's in C#.NET and later on it uses Unity.

它在 C#.NET 中,后来使用 Unity。

Update after comment:

评论后更新:

Relevant section of article

文章相关部分

"Observe the following changes to the original design:

“观察原始设计的以下变化:

quick graph of situation

情况快速图

We went for the “Constructor Injection” pattern to implement DI and the refactoring steps were:

我们采用“构造函数注入”模式来实现 DI,重构步骤是:

  1. Abstract the interface of CardPresenceChecker by creating Interface ICardPresenceChecker;
  2. Make explicit that this CardPresenceChecker only works for the library of Company X, by changing its name to XCardPresenceChecker ;
  3. Have XCardPresenceChecker implement Interface ICardPresenceChecker ;
  4. Abstract the property of LogInService to be of type ICardPresenceChecker instead of ‘knowing' exactly which implementation is held aboard;
  5. And last but not least, demand from users (other developers) of LogInService that they provide any class that at least implements ICardPresenceChecker so that LogInService can do its thing.
  1. 通过创建Interface ICardPresenceChecker来抽象CardPresenceChecker的接口;
  2. 通过将其名称更改为 XCardPresenceChecker ,明确此 CardPresenceChecker 仅适用于 X 公司的图书馆;
  3. 让 XCardPresenceChecker 实现接口 ICardPresenceChecker ;
  4. 将 LogInService 的属性抽象为 ICardPresenceChecker 类型,而不是“知道”具体是哪个实现;
  5. 最后但并非最不重要的是,LogInService 的用户(其他开发人员)要求他们提供任何至少实现 ICardPresenceChecker 的类,以便 LogInService 可以完成它的工作。

LogInService's constructor looks like:

LogInService 的构造函数如下所示:

this.myCardPresenceChecker = cardPresenceChecker;
this.myCardPresenceChecker.CardIn += MyCardPresenceChecker_CardIn;
this.myCardPresenceChecker.CardOut += MyCardPresenceChecker_CardOut;
this.myCardPresenceChecker.Init();

So where do you provide LogInService with an implementation of ICardPresenceChecker? You usually want this ‘mapping' (in this example we would ‘map' ICardPresenceChecker to XCardPresenceChecker) at one central place at the startup of an application, known conceptually as the “Composition Root”. For an ol' regular Console Application that could be the void Main in the Program class. So for this example, this piece of code would be used at the aformentioned place:

那么您在哪里为 LogInService 提供 ICardPresenceChecker 的实现呢?您通常需要在应用程序启动时的一个中心位置(概念上称为“组合根”)进行此“映射”(在本示例中,我们将把 ICardPresenceChecker '映射'到 XCardPresenceChecker)。对于可能是 Program 类中的 void Main 的常规控制台应用程序。所以对于这个例子,这段代码将用于上述地方:

LogInService logInService = new LogInService(new XCardPresenceChecker());"

LogInService logInService = new LogInService(new XCardPresenceChecker());"

回答by dr. evil

I've got Dependency Injection with a really simple example like this.

我有一个像这样非常简单的例子的依赖注入。

See the class below, you'll get the whole idea. As you see unless you supply file it will use the default one settings file, but you can set a settings file and then the class will use it.

看看下面的课程,你就会明白整个想法。如您所见,除非您提供文件,否则它将使用默认的一个设置文件,但您可以设置一个设置文件,然后类将使用它。

Public Class ProcessFile

Private _SettingsFile As String = "settings.bin"

Public Sub New()
End Sub

Public Sub New(settings As String)
_SettingsFile= settings
End Sub

Public Function ReadFile() As String 
'Do stuff based on the settings stored in the _SettingsFile 
End Function

End Class

Obviously this is the most basic case. In real world you can do the same thing with class types, such as you've got Database Layer and you can switch the underlying database dll by doing dependency injection and you code will work with any database as soon as you can provide the valid class (a class which implements the interface you are using).

显然,这是最基本的情况。在现实世界中,你可以对类类型做同样的事情,比如你有数据库层,你可以通过依赖注入来切换底层数据库 dll,只要你能提供有效的类,你的代码就可以与任何数据库一起使用(实现您正在使用的接口的类)。

After got the basic you can do this on larger scope and totally independent from the application by using DI frameworks like unity.

获得基本知识后,您可以使用 DI 框架(如 unity)在更大范围内完成此操作,并且完全独立于应用程序。

回答by Steve

You essentially pass in all necessary objects in the constructor. Alternatively, you can resolve them at runtime using an interface resolver (although this is less typesafe). You can find excellent examples at the Ninject website for the first approach, and good examples at the Unitywebsite for the second approach. This avoid the need for singletons and allows you to easily drop in a replacement object that conforms to the desired interface

您本质上是在构造函数中传入所有必需的对象。或者,您可以在运行时使用接口解析器解析它们(尽管这不太安全)。您可以在 Ninject 网站上找到第一种方法的优秀示例,也可以在Unity网站上找到第二种方法的优秀示例。这避免了对单例的需求,并允许您轻松放入符合所需界面的替换对象

回答by ACE

Install below Nuget packages in main mvc4 project name SampleDependency. Unity.mvc4, unity.webapi and MicrosoftAsp.Net Web API 2.2 Web host

安装在主 mvc4 项目名称 SampleDependency 中的 Nuget 包下面。Unity.mvc4、unity.webapi 和 MicrosoftAsp.Net Web API 2.2 Web 主机

In web project

在网络项目中

public static class Bootstrapper
{
    public static IUnityContainer Initialise()
    {
        var container = BuildUnityContainer();

        DependencyResolver.SetResolver(new UnityDependencyResolver(container));
        GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container);

        return container;
    }

    private static IUnityContainer BuildUnityContainer()
    {
        var container = new UnityContainer();

        // register all your components with the container here
        // it is NOT necessary to register your controllers

        // e.g. container.RegisterType<ITestService, TestService>();
        container.RegisterType<IUserDetailLogic, UserDetailLogic>();
        container.RegisterType<IUserData, UserData>();

        RegisterTypes(container);

        return container;
    }
    public static void RegisterTypes(IUnityContainer container)
    {

    }
}

回答by Ace

Create DB layer project(class library) and add below code in it.

创建 DB 层项目(类库)并在其中添加以下代码。

public class UserData : IUserData
{
    public string getUserDetails()
    {
        return "Asif";
    }
}

public interface IUserData
{
    string getUserDetails();
}

回答by Ace

Add bussiness logic project of type class library and add below code in it. public class UserDetailLogic : IUserDetailLogic { private IUserData _userData = null;

添加类型类库的业务逻辑项目,并在其中添加以下代码。公共类 UserDetailLogic : IUserDetailLogic { private IUserData _userData = null;

    public UserDetailLogic(IUserData userData)
    {
        _userData = userData;
    }
    public string getUserDetails()
    {
        return _userData.getUserDetails();
    }
}

public interface IUserDetailLogic
{
    string getUserDetails();
}

In you main project add below code in home controller.

在您的主项目中,在主控制器中添加以下代码。

public class HomeController : Controller { private readonly IUserDetailLogic _userDetailLogic;

公共类 HomeController :控制器 { 私有只读 IUserDetailLogic _userDetailLogic;

    public HomeController(IUserDetailLogic userDetailLogic)
    {
        _userDetailLogic = userDetailLogic;
    }

    public ActionResult Index()
    {
        ViewBag.Message = "Modify this template to jump-start your ASP.NET MVC application.";
        string str = _userDetailLogic.getUserDetails();
        return View();
    }

    public ActionResult About()
    {
        ViewBag.Message = "Your app description page.";

        return View();
    }

    public ActionResult Contact()
    {
        ViewBag.Message = "Your contact page.";

        return View();
    }
}