无法将A <b>隐式转换为A <c <d >>,其中B继承自C <d>

时间:2018-08-18 08:41:07

标签: c# generics inheritance architecture

我正在构建一种库,用于根据某些规则在文档中执行文本替换。我们建立了一个POC,现在我正在尝试创建一个尽可能通用的库。

继承只有一个问题:

这是我正在处理的类/接口的简化表示:

public interface IRule {}

public interface IReplaceRule<T> : IRule 
{
    T ReplaceValue { get; set; }
}

public class CachedRules<T> where T : IReplaceRule<object>
{
    #region Props
    public T RuleTemplate { get; set; }

    public IDictionary<string, T> RuleList { get; private set; } = null;
    #endregion

    public void SetRuleList(IDictionary<string, T> ruleList) { ... }

    public bool ContainsRuleByKey(string key) { ... }

    public bool TryGetRuleValueByKey(string key, out T rule) { ... }
}

public class SingleRowRule : IReplaceRule<string> { ... }

我还有一个类,类似于规则存储库,并且在其中可以根据需要添加任意数量的CachedRules

public class RulesStorage : AbstractRulesStorage
{
    private CachedRules<SingleRowRule> singleRowRules;

    public RulesStorage() { ... }

    // Bunch of methods not useful for this question

    // Here I need to return a list of ChachedRule, but just ofr testing I tried to return only one
    public CachedRules<IReplaceRule<object>> GetCachedReplaceRules()
    {
        return singleRowRules;
    }
}

在此类中,我需要一个方法来返回在CachedRules中声明的所有RulesStorage: 不幸的是RulesStorage.GetCachedReplaceRules方法给我这个错误:

  

无法将类型TestLib.Model.CachedRules<TestLib.Rules.SingleRowRule>隐式转换为TestLib.Model.CachedRules<TestLib.Abstractions.IReplaceRule<object>

我真的不喜欢我必须放<object>的事实,因为IReplaceRule需要一个泛型,而且我被卡住了,因为我不知道如何返回此{{ 1}},而不会出现此编译错误。

你有什么主意吗?您认为我是否必须以不同的方式组织代码?

希望我已经说清楚了,谢谢!!

1 个答案:

答案 0 :(得分:0)

您可以执行IReplaceRule<object>IEnumerable<T>继承的方式来代替IEnumerable。进行了这些细微调整之后,我创建了一个从TIReplaceRule的隐式转换器,并且适当的约束现在可以确保我实际上可以安全地执行此操作。

我假设您有理由拥有private CachedRules<SingleRowRule> singleRowRules;并且不能仅使用private CachedRules<IReplaceRule> singleRowRules;来消除这种额外的转换跃迁。

代码:

public interface IReplaceRule : IRule { object ReplaceValue { get; set; } }

public interface IReplaceRule<T> : IReplaceRule { new T ReplaceValue { get; set; } }

public class CachedRules<T> where T : IReplaceRule
{
    public IDictionary<string, T> RuleList { get; private set; } = new Dictionary<string, T>();

    //The key ingredient for a nice experience instead of just doing this in the method
    public static implicit operator CachedRules<IReplaceRule>(CachedRules<T> rules)
        => new CachedRules<IReplaceRule> { RuleList = rules.RuleList.ToDictionary(x => x.Key, x => x.Value as IReplaceRule) };
}

public class SingleRowRule : IReplaceRule<string>
{
    public string ReplaceValue { get; set; }
    object IReplaceRule.ReplaceValue { get => ReplaceValue; set => ReplaceValue = value as string; }
}

public class RulesStorage
{
    private CachedRules<SingleRowRule> singleRowRules = new CachedRules<UserQuery.SingleRowRule>();

    //FIXME: just for testing purposes
    public RulesStorage() => singleRowRules.RuleList.Add("Hello", new SingleRowRule { ReplaceValue = "World" });

    // Here I need to return a list of ChachedRule, but just ofr testing I tried to return only one
    public CachedRules<IReplaceRule> GetCachedReplaceRules() => singleRowRules;
}