我需要有关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,或者如果程序集实现是针对平面文件,那么它将把它保存到平面文件。
但我的要求与位差异相同,例如我想根据国家/地区代码保存数据。所以我需要在代码和配置文件中进行更改,因此我可以根据国家/地区代码保存数据。请帮我解决代码问题概念。感谢
答案 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模式。