使用示例c#在.NET中进行依赖注入

时间:2013-01-10 14:11:12

标签: c# dependency-injection unity-container

我需要有关DI的帮助,但我从未使用过DI。所以概念对我来说是新的。我的问题是假设我需要将日志保存到数据库或平面文件或者可能是Windows事件日志。 基于少数参数我想将日志数据保存到DB或平面文件或事件日志

例如,如果国家/地区代码是GBR 然后事件日志将保存到DB。如果国家代码是美国 然后事件日志将保存到平面文件中。如果国家代码是美国 然后事件日志将保存到Windows事件日志。

我得到了一个类似的代码,用DI模式实现了上述问题。这是代码

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>

但上面这个代码的问题一次只会做一件事。如果程序集实现是针对DB的,那么它会将其保存到DB,或者如果程序集实现是针对平面文件,那么它将把它保存到平面文件。

但我的要求与位差异相同,例如我想根据国家/地区代码保存数据。所以我需要在代码和配置文件中进行更改,因此我可以根据国家/地区代码保存数据。请帮我解决代码问题概念。感谢

2 个答案:

答案 0 :(得分:3)

DI框架有用的原因是避免需要进行大量的样板工厂实现,如下所示:

public class SomeFactory
{
    public SomeClass GetSomeClass()
    {
          return new SomeClass(new SomeDep1(), new SomeDep2(new SomeInnerDep()));
    }
}

如果您在工厂中没有简单的需求,请不要回避仅仅写出您需要的东西。在您的示例中:

public class ILogFactory
{
  public ILog Create(CountryCode code)
  {
     if(code == CountryCode.GBR) return new EvenLogger();

     if(code == CountryCode.UK) return new DatabaseLogger(_providerFactory());

     ///etc...
  }
}

编辑:另请注意,我写了一个ILog工厂而不是SomeClassFactory。这样工厂的用户可以耦合到接口,而不是具体的实例。这在DI中非常有用,通常可以替代所需的具体类型。

答案 1 :(得分:2)

你必须做两件事: 1)在Unity容器中注册两个具有特定名称的映射。像这样修改你的xml配置:

<type type="MyAssembly.ILog,MyAssembly"
            mapTo="MyImplementations.SqlLog, MyImplementations"
            name="sql">
        <lifetime type="singleton"/>
      </type>
<type type="MyAssembly.ILog,MyAssembly"
            mapTo="MyImplementations.FileLog, MyImplementations"
            name="file">
        <lifetime type="singleton"/>
      </type>

(注意“type”元素的“name”属性)

然后解决你的依赖关系(抱歉,我不知道DependencyInjector类,所以我使用Unity容器(Microsoft.Practices.Unity.IUnityContainer):

// create and initialize unity container once somewhere in startup code.
var сontainer = new UnityContainer();
container.LoadConfiguration(); // load unity configuration from application xml config 

// then use container to resolve dependencies.
if (CountryCodeSaysToUseDb())
   return container.Resolve<MyAssembly.ILog>("sql");
if (ContryCodeSaysToUseFile())
   return container.Resolve<MyAssembly.ILog>("file");

但要小心,因为通过在您自己的代码中明确选择特定的实现,您正在破坏DI模式。