我有以下课程
public interface IEngine
{
void DoSomething();
}
public interface IEngineFactory<T> where T : IEngine
{
T Create();
}
public class FooEngine : IEngine
{
public FooEngine(string id)
{
// do something with the id
}
public void DoSomething()
{
// do something with the id
}
}
public class EnginesSection : ConfigurationSection
{
[ConfigurationProperty("engines", IsRequired = true)]
public EnginesElement Engines
{
get { return (EnginesElement) this["engines"]; }
set { this["engines"] = value; }
}
}
public class EnginesElement : ConfigurationElement
{
[ConfigurationProperty("foo", IsRequired = true)]
public FooEngineElement Foo
{
get { return (FooEngineElement) this["foo"]; }
set { this["foo"] = value; }
}
}
public abstract class EngineElement : ConfigurationElement, IEngineFactory<T> where T : IEngine
{
public abstract T Create();
}
public class FooEngineElement : EngineElement<FooEngine>
{
[ConfigurationProperty("id", IsRequired = true)]
public string Id
{
get { return (string) this["id"]; }
set { this["id"] = value; }
}
public FooEngine Create()
{
return new FooEngine(Id);
}
}
包含
的web.config<engineSection>
<engines>
<foo id="asdf" />
</engines>
<locales>
<engine locale="en-US" type="foo"/>
<engine locale="en-CA" type="foo"/>
</locales>
</engineSection>
我的目的是将locales
部分中指定的区域设置映射到相应的引擎。选择的引擎是config元素创建的引擎。因此type
元素中的engine
值是engines
部分中的元素名称。将来会有不同的引擎有不同的参数。每个区域设置可能只有一个引擎。
例如
<engineSection>
<engines>
<foo id="asdf" />
<bar timeout="00:00:00.300" workers="6" />
</engines>
<locales>
<engine locale="en-US" type="foo"/>
<engine locale="en-CA" type="foo"/>
<engine locale="en-GB" type="bar"/>
</locales>
</engineSection>
我尝试实现这一目标的方法是:
IDictionary<string, string> engineLocales = GetEngineLocalesFromConfig();
IDictionary<string, IEngine> engines = GetEnginesFromConfig();
IDictionary<string, IEngine> mappedEngines = MapEngines(engineLocales, engines);
// ...
private static IDictionary<string, IEngine> GetEnginesFromConfig(EnginesElement enginesElement)
{
var engines = new Dictionary<string, IEngine>();
foreach (PropertyInformation property in enginesElement.ElementInformation.Properties)
{
var factory = property.Value as EngineElement<IEngine>;
engines[property.Name] = factory.Create();
}
return engines;
}
所以我们有
|----engineLocales-----|
|---------engines---------|
+----------------------------------+
| locale | engine type | engine |
+--------+-------------+-----------+
| en-US | foo | FooEngine |
| en-CA | foo | FooEngine |
| en-GB | bar | BarEngine |
+----------------------------------+
但是,这不起作用,因为从EngineElement<FooEngine>
到EngineElement<IEngine>
的情况失败了。我不希望将这些事情映射到必要的代码知道实现。
有没有办法在不知道具体实现的情况下实现这种类型的动态映射?如果没有,我有什么替代方案?
答案 0 :(得分:0)
通过在调用堆栈中一直使用IEngineFactory
,我能够获得所需的行为。因为我不关心它的实际实现,只关心它Create
的能力。
我将IEngineFactory
更改为
public interface IEngineFactory
{
IEngine Create();
}
EngineElement
到
public abstract class EngineElement : ConfigurationElement, IEngineFactory
{
public abstract IEngine Create();
}
FooEngineElement
到
public class FooEngineElement : EngineElement
{
[ConfigurationProperty("id", IsRequired = true)]
public string Id
{
get { return (string) this["id"]; }
set { this["id"] = value; }
}
public override IEngine Create()
{
return new FooEngine(Id);
}
}
创建工厂
var factory = property.Value as EngineElement;