我有两个界面:
public interface IDbModel {}
public interface IDmModel {}
从这个派生的类:
public class DbModel : IDbModel {}
public class DmModel : IDmModel {}
public class Middle { }
此外,我还有两个限制接口:
public interface IRule { }
public interface IRule<in TInput, out TOutput> : IRule
where TInput : IDmModel
where TOutput : IDbModel
{
TOutput Apply(TInput elem);
}
从这个接口派生出一个抽象类:
public abstract class Rule<TDmModel, TMiddle, TDb> : IRule<TDmModel, TDb>
where TDmModel : IDmModel
where TDb : IDbModel
{
private readonly Func<TDmModel, TMiddle> _rule;
protected Rule(Func<TDmModel, TMiddle> rule) { _rule = rule; }
protected abstract TDb Apply(TMiddle transformedMessage);
public TDb Apply(TDmModel elem) { ... }
}
在此之后,我创建了两个派生自此抽象类的类:
public class RuleA : Rule<DmModel, Middle, DbModel>
{
public RuleA(Func<DmModel, Middle> rule) : base(rule) {}
protected override DbMode Apply(Middle transformedMessage) { ... }
}
public class RuleB : RuleA
{
public RuleB() : base((dm) => new Middle()) {}
}
规则B:规则A:规则&lt; DmModel,Middle,DbModel&gt; :IRule&lt; IDmModel,IDbModel&gt; :IRule
当我尝试将RuleB
的对象转换为IRule<IDmModel, IDbModel>
时会出现未处理的异常
无法将类型为'ParsreCombinators.RuleB'的对象转换为'ParsreCombinators.IRule`2 [ParsreCombinators.IDmModel,ParsreCombinators.IDbModel]'。
var ruleB = (IRule<IDmModel, IDbModel>)new RuleB(); // Exception
IDbModel dbModel = ruleB.Apply(new DmModel());
有什么问题
为了让这个例子不那么混乱我简化它:
修改
在我理解的答案之后,问题是什么,并使示例不那么混乱,我简化它:
public interface IDbModel {}
public interface IDmModel {}
public class DbModel : IDbModel {}
public class DmModel : IDmModel {}
public interface IRule<in TInput, out TOutput>
where TInput : IDmModel
where TOutput : IDbModel
{
TOutput Apply(TInput elem);
}
public class RuleA : IRule<DmModel, DbModel>
{
public DbModel Apply(DmModel elem) { ... }
}
var ruleA = (IRule<IDmModel, IDbModel>)new RuleA(); // Exception
答案 0 :(得分:7)
你到那里的间接程度很高......
问题在于:
public abstract class Rule<TDmModel, TMiddle, TDb> : IRule<TDmModel, TDb>
where TDmModel : IDmModel
where TDb : IDbModel
public class RuleA : Rule<DmModel, Middle, DbMode>
public class RuleB : RuleA
...
var ruleB = (IRule<IDmModel, IDbModel>)new RuleB();
RuleB实现了IRule&lt; DmModel,DbMode&gt;
这不能转换为IRule&lt; IDmModel,IDbModel&gt;。 C#不支持这种类型的转换。出于同样的原因,您无法执行List<object> b = (List<object>)new List<string>();
(Gives“无法将类型'System.Collections.Generic.List&lt; string&gt;转换为System.Collections.Generic.List&lt; object&gt;。”)
这是协方差问题。
以下是Microsoft提供的有关此主题的更多信息:https://docs.microsoft.com/en-us/dotnet/standard/generics/covariance-and-contravariance
答案 1 :(得分:3)
这是一个非常令人困惑的例子,但我相信问题在于你是否正在转换为泛型类型并给它接口,当你派生的类强制你使用DmModel和DbMode时。
也许这就是你的意思:
var ruleB = (IRule<DmModel, DbMode>)new RuleB();
编译得很好,我用这种方式构建你的课程,这是除了重组之外的唯一选择。
答案 2 :(得分:3)
你的界面IRule<in TInput, out TOutput>
是协变的和逆变,这意味着你不能协变地投射它。逆变阻止了这一点。
基本上,您的赋值var dbModel = (IRule<IDmModel, IDbModel>)new RuleB();
断言dbModel必须接受任何 IDmModel
参数。不幸的是,事实并非如此;由于DmModel
的具体形式,实例必须可分配给RuleA
,因此IDmModel
的其他衍生产品将失败。