looking for various way of implemention Dependency

2019-08-12 23:29发布

问题:

i am new in Dependency injection. i just got familiar how to implement dependency injection with Interface injection but we know that Dependency injection can be implemented with three way or may be more and those are :-

  1. Interface injection: The service provides an interface which consumers must implement. The interface exposes specific behaviors at run time.
  2. Setter injection: The dependent object exposes a “setter” method to inject the dependency.
  3. Constructor injection: Dependencies are injected through the class constructor

so i am looking for few sample code which can help me to understand how to implement Dependency injection using either Setter injection or Constructor injection using unity. any help with small small code for different way of implementing dependency injection will be appreciated.

i know only Interface injection using unity. here is my code which works fine using Interface injection with unity.

public interface ILogger
{
     void Write(string message);
}

We have define three classes as follows.

public class FileLogger : ILogger
{
     public void Write(string message)
     {
          //Do somthing
     }
}

public class SQLLogger : ILogger
{
     public void Write(string message)
     {
          //Do somthing
     }
}

public class WindowsEventLogger : ILogger
{
     public void Write(string message)
     {
          //Do somthing
     }
}

Need to register and map these classes with interface in configuration file (i.e. app.config).

<configSections>
    <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/>
  </configSections>

  <unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
    <alias type="UnityTest.ILogger, UnityTest" alias="ILogger" />
    <namespace name="UnityTest"/>

    <container>
      <register mapTo="UnityTest.FileLogger, UnityTest" name="MyFileLogger" type="ILogger"/>
      <register mapTo="UnityTest.SQLLogger, UnityTest" name="MySQLLogger" type="ILogger"/>
      <register mapTo="UnityTest.WindowsEventLogger, UnityTest" name="MyWindowsEventLogger" type="ILogger"/>
    </container>
</unity>

Note: name attribute is important in register tag.

Finally we have to use this map into our code. So, we have to know that for which one is preferable for specific country.

A dictionary object can be use to keep this mapping as follows.

IDictionary<string, string> loggers = new Dictionary<string, string>();
loggers.Add("USA", "MyFileLogger");
loggers.Add("GBR", "MySQLLogger");
loggers.Add("IN", "MyWindowsEventLogger");

You can populate it from database, xml or another source, and now it's time to call the Write method.

IUnityContainer container = new UnityContainer();
container.LoadConfiguration();

ILogger logger = container.Resolve<ILogger>(loggers[objUser.countryCode]);
logger.Write("Hello World");

New question

I found a sample code for construction injection with unity but still one thing is not clear. Here is the code.

public class CustomerService
{
  public CustomerService(LoggingService myServiceInstance)
  { 
    // work with the dependent instance
    myServiceInstance.WriteToLog("SomeValue");
  }
} 

IUnityContainer uContainer = new UnityContainer();
CustomerService myInstance = uContainer.Resolve<CustomerService>();

When we write uContainer.Resolve<CustomerService>(); then we are not sending any instance of LoggingService class then how we can create instance of CustomerService class because it's constructor require instance of LoggingService.

This area is not clear. Please explain to me how it works.

Another question is [Dependency] attribute: what it does, and when a method needs to be decorated with the [Dependency] attribute.

回答1:

With your code as a base.

if you have some class that depends on ILogger, and you have a default registration for ILogger (a registration without name)

IUnityContainer container = new UnityContainer();

//fixed
//by default RegisterType will create new instance of the type every time 
//the container resolves the dependancy 
container.RegisterType<ILogger,SomeLoggerImplementation>();
container.RegisterType<Foo>();
container.RegisterType<Bar>();

//will create a new instance of SomeLoggerImplementation using a default ctor, pass it to the constructor of Foo and return the instance of Foo
//if SomeLoggerImplementation has some other dependancies they can be registered in the container too! 
var foo = container.Resolve<Foo>();

//will create a new instance of SomeLoggerImplementation using a default ctor, create a new instance of Bar, 
//Set the value of the Property Logger (but not the Logger2), and return the instance of Bar
var bar = container.Resolve<Bar>();

//Constructor injection
public class Foo
{
    private ILogger _logger;
    public Foo(ILogger logger)
    {
        //if Foo is resolved from the container , the value for the logger parameter will be provided from the container
        _logger = logger;
    }
}


//property injection
public class Bar
{
    //If Bar is resolvced from the container the value for the Logger property will also  be provided from the container
    [Dependency]
    public ILogger Logger { get; set; }

    //this will not be injected
    public ILogger Logger2 { get; set; }

    public Bar()
    {
    }
}


回答2:

First register the classes to be solved to unity (in this case register Test class to unity). When you try to resolve an instance of Test class using unity, it will resolve ILogger too. You may refer to injection attributes from msdn

setter injection;

public class Test : ITest
{
    [Dependency("MyFileLogger")]
    public ILogger Logger
    {
       get { return iLogger; }
       set { iLogger = value; }
    }
}

constructor injection;

public class Test : ITest
{
    public Test([Dependency("MyFileLogger")] ILogger logger)
    {
         //// you will have an instance of MyFileLogger
    }
}

For the second part of your question, since LoggingService is also registered to unity, when CustomerService is tried to be resolved, it will use constructor injection to resolve the LoggingService parameter. In other words, when container tries to resolve CustomerService; it understands that LoggingService is needed to resolve it. Then it first resolves LoggingService parameter and then tries to resolve CustomerService.