无法将通用类型作为父类型

时间:2016-08-12 01:57:50

标签: c#

我有以下课程

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>的情况失败了。我不希望将这些事情映射到必要的代码知道实现。

有没有办法在不知道具体实现的情况下实现这种类型的动态映射?如果没有,我有什么替代方案?

1 个答案:

答案 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;