【问题标题】:Cannot implicitly convert A<B> to A<C<D>> where B inherit from C<D>无法将 A<B> 隐式转换为 A<C<D>>,其中 B 从 C<D> 继承
【发布时间】:2018-08-18 08:41:06
【问题描述】:

我正在构建一种库来根据某些规则在文档中执行文本替换。我们构建了一个 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;
    }
}

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

无法将类型 TestLib.Model.CachedRules&lt;TestLib.Rules.SingleRowRule&gt; 隐式转换为 TestLib.Model.CachedRules&lt;TestLib.Abstractions.IReplaceRule&lt;object&gt;

我真的不喜欢我必须输入 &lt;object&gt; 的事实,因为 IReplaceRule 需要一个泛型,而且我被卡住了,因为我不知道如何返回这个 CachedRules 列表而不得到这个编译错误。

你有什么想法吗?在您看来,我是否必须以不同的方式组织代码?

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

【问题讨论】:

    标签: c# generics inheritance architecture


    【解决方案1】:

    您可以使用IEnumerable&lt;T&gt; 继承自IEnumerable 的方式来代替IReplaceRule&lt;object&gt;。有了这个小的调整,我创建了一个隐式转换器来从 T 到 IReplaceRule 并且现在的约束确保我实际上可以安全地做到这一点。

    我假设您有理由拥有 private CachedRules&lt;SingleRowRule&gt; singleRowRules;,并且不能只使用 private CachedRules&lt;IReplaceRule&gt; 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;
    }
    

    【讨论】:

    • 感谢您的回答 Maverik!我会尽快尝试你的建议,我会通知你的!
    猜你喜欢
    • 1970-01-01
    • 2018-09-14
    • 1970-01-01
    • 1970-01-01
    • 2022-01-21
    • 1970-01-01
    • 1970-01-01
    • 2012-01-27
    • 1970-01-01
    相关资源
    最近更新 更多