Внедрение зависимостей в .NET с примерами? - PullRequest
28 голосов
/ 13 апреля 2009

Может кто-нибудь объяснить внедрение зависимости с помощью базового примера .NET и предоставить несколько ссылок на ресурсы .NET для расширения по теме?

Это не дубликат Что такое внедрение зависимостей? , потому что я спрашиваю о конкретных примерах и ресурсах .NET.

Ответы [ 8 ]

33 голосов
/ 13 апреля 2009

Вот типичный пример. Вам необходимо войти в свое приложение. Но во время разработки вы не уверены, хочет ли клиент регистрироваться в базе данных, файлах или журнале событий.

Итак, вы хотите использовать DI, чтобы отложить этот выбор до того, который может быть настроен клиентом.

Это какой-то псевдокод (примерно на основе Unity):

Вы создаете интерфейс регистрации:

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

затем используйте этот интерфейс в ваших классах

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

внедрить эти зависимости во время выполнения

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

и экземпляр настроен в 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>

Теперь, если вы хотите изменить тип регистратора, просто зайдите в конфигурацию и укажите другой тип.

32 голосов
/ 14 ноября 2009

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");
  }
}

Это, для меня, очень бегло читается, прежде чем вы начнете свое додзё, вы можете решить, как вооружить своих самураев.

3 голосов
/ 16 июня 2015

Я думаю, что важно сначала изучить DI без контейнеров IoC. Поэтому я написал пример, который медленно переходит в контейнер IoC. Это реальный пример из моей работы, но он все еще достаточно прост, чтобы новички могли понять суть DI. Вы можете найти его здесь: https://dannyvanderkraan.wordpress.com/2015/06/15/real-world-example-of-dependeny-injection/

Он находится в C # .NET, а позже использует Unity.

Обновление после комментария:

Соответствующий раздел статьи

"Обратите внимание на следующие изменения в оригинальном дизайне:

quick graph of situation

Мы использовали шаблон «Внедрение в конструктор» для реализации DI, и шаги по рефакторингу были:

  1. Аннотация интерфейс CardPresenceChecker путем создания интерфейса ICardPresenceChecker;
  2. Укажите, что этот CardPresenceChecker работает только для библиотеки компании X, изменив его имя на XCardPresenceChecker;
  3. У XCardPresenceChecker реализован интерфейс ICardPresenceChecker;
  4. Абстрагируйте свойство LogInService от типа ICardPresenceChecker вместо того, чтобы «знать», какой именно реализация проводится на борту;
  5. И, наконец, что не менее важно, требуйте от пользователей (других разработчиков) LogInService, чтобы они предоставили любой класс, который хотя бы реализует ICardPresenceChecker, чтобы LogInService мог делать свое дело.

Конструктор LogInService выглядит так:

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

Так где же вы предоставляете LogInService реализацию ICardPresenceChecker? Обычно вам требуется это «отображение» (в этом примере мы «сопоставим» ICardPresenceChecker с XCardPresenceChecker) в одном центральном месте при запуске приложения, концептуально известном как «корень композиции». Для обычного консольного приложения, которое может быть пустым Main в классе Program. Таким образом, для этого примера этот фрагмент кода будет использоваться в указанном месте:

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

1 голос
/ 13 апреля 2009

У меня есть Dependency Injection с таким простым примером, как этот.

См. Класс ниже, вы получите всю идею. Как вы видите, если вы не предоставите файл, он будет использовать один файл настроек по умолчанию, но вы можете установить файл настроек, и тогда класс будет использовать его.

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

Очевидно, что это самый основной случай. В реальном мире вы можете делать то же самое с типами классов, например, у вас есть уровень базы данных, и вы можете переключать базовую dll базы данных путем внедрения зависимостей, и ваш код будет работать с любой базой данных, как только вы сможете предоставить действительный класс. (класс, реализующий используемый вами интерфейс).

После того, как вы получили базовые знания, вы можете сделать это в большем объеме и полностью независимы от приложения, используя интегрированные среды DI, такие как Unity.

0 голосов
/ 04 ноября 2014

Добавьте проект бизнес-логики из библиотеки классов типов и добавьте в него код ниже. открытый класс UserDetailLogic: IUserDetailLogic { private IUserData _userData = null;

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

public interface IUserDetailLogic
{
    string getUserDetails();
}

В вашем основном проекте добавьте ниже код в домашний контроллер.

публичный класс 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();
    }
}
0 голосов
/ 04 ноября 2014

Создайте проект слоя БД (библиотеку классов) и добавьте в него код ниже.

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

public interface IUserData
{
    string getUserDetails();
}
0 голосов
/ 03 ноября 2014

Установить ниже пакетов Nuget в основном проекте mvc4 с именем SampleDependency. Веб-хост Unity.mvc4, unity.webapi и MicrosoftAsp.Net Web API 2.2

В веб-проекте

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)
    {

    }
}
0 голосов
/ 13 апреля 2009

Вы по существу передаете все необходимые объекты в конструкторе. Кроме того, вы можете разрешить их во время выполнения с помощью распознавателя интерфейса (хотя это менее безопасно для типов). Вы можете найти отличные примеры на веб-сайте Ninject для первого подхода и хорошие примеры на веб-сайте Unity для второго подхода. Это исключает необходимость использования синглетонов и позволяет легко вставить замещающий объект, соответствующий требуемому интерфейсу

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...