无法将泛型类型的对象强制转换为泛型接口 C#



我有两个接口:

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 : 规则<DmModel,中间,DbModel> : IRule

<IDmModel,IDbModel> : 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

这是你到达那里的很多间接级别......

问题是:

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<DmModel,>

这不能强制转换为IRule<IDmModel,IDbModel>。 C# 不支持这种类型的强制转换。 出于同样的原因,您不能执行List<object> b = (List<object>)new List<string>();(给出"无法将类型'System.Collections.Generic.List转换为System.Collections.Generic.List

这是协方差的问题。

以下是Microsoft关于该主题的更多信息:https://learn.microsoft.com/en-us/dotnet/standard/generics/covariance-and-contravariance

这是一个非常令人困惑的例子,但我相信问题是当你派生的类迫使你使用 DmModel 和 DbMode 时,你正在强制转换为泛型类型并为其提供接口。

也许这就是你的意思:

var ruleB = (IRule<DmModel, DbMode>)new RuleB();

编译得很好,我用这种方式构建您的类,是重组之外的唯一选择。

你的接口IRule<in TInput, out TOutput>既是协变,也是逆变的,这意味着你不能协变转换它。 逆变阻止了这一点。

基本上,赋值var dbModel = (IRule<IDmModel, IDbModel>)new RuleB();断言 dbModel 必须接受任何IDmModel参数。 不幸的是,事实并非如此;由于RuleA的具体形式,实例必须可分配给DmModel,因此IDmModel的其他导数将失败。

最新更新