简体   繁体   English

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

[英]Unable to cast object of generic type to generic interface C#

I have two interfaces: 我有两个接口:

public interface IDbModel {}
public interface IDmModel {}

And classes derived from this: 和派生自这的类:

public class DbModel : IDbModel {}
public class DmModel : IDmModel {}
public class Middle { }

Also I have two interfaces with restrictions: 另外我有两个限制接口:

public interface IRule { }
public interface IRule<in TInput, out TOutput> : IRule
    where TInput : IDmModel
    where TOutput : IDbModel
{
    TOutput Apply(TInput elem);
}

And one abstract class derived from this interface: 从这个接口派生出一个抽象类:

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) { ... }
}

After this I created two classes derived from this abstract class: 在此之后,我创建了两个派生自此抽象类的类:

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()) {}
}

RuleB : RuleA : Rule< DmModel,Middle,DbModel > : IRule< IDmModel,IDbModel > : IRule RuleB:RuleA:Rule <DmModel,Middle,DbModel>:IRule <IDmModel,IDbModel>:IRule

And when I try to cast object of RuleB to IRule<IDmModel, IDbModel> occours unhandled exception 当我尝试将RuleB对象RuleBIRule<IDmModel, IDbModel>出现未处理的异常

Unable to cast object of type 'ParsreCombinators.RuleB' to type 'ParsreCombinators.IRule`2[ParsreCombinators.IDmModel,ParsreCombinators.IDbModel]'. 无法将类型为'ParsreCombinators.RuleB'的对象转换为'ParsreCombinators.IRule`2 [ParsreCombinators.IDmModel,ParsreCombinators.IDbModel]'。

var ruleB = (IRule<IDmModel, IDbModel>)new RuleB(); // Exception 
IDbModel dbModel = ruleB.Apply(new DmModel());

What wrong with this 有什么不对这个

To make the example less confusing I simplify it: 为了减少混乱,我简化了它:

EDIT: 编辑:

After the answers I understood, what is the problem and to make the example less confusing I simplify it: 在我理解了答案之后,问题是什么,并使示例不那么混乱我简化它:

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

That's a lot of levels of indirection you got there... 你到那里的间接程度很高......

Here's the issue: 这是问题所在:

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 implements IRule<DmModel, DbMode> RuleB实现了IRule <DmModel,DbMode>

This cannot be cast to IRule<IDmModel, IDbModel>. 这不能转换为IRule <IDmModel,IDbModel>。 C# does not support this type of casting. C#不支持这种类型的转换。 For the same reason, you cannot do List<object> b = (List<object>)new List<string>(); 出于同样的原因,你不能做List<object> b = (List<object>)new List<string>(); (Gives "Cannot convert type 'System.Collections.Generic.List<string> to System.Collections.Generic.List<object>.") (提供“无法将类型'System.Collections.Generic.List <string>转换为System.Collections.Generic.List <object>。”)

This is an issue with covariance. 这是协方差的问题。

Here is some more information from Microsoft on the subject: https://docs.microsoft.com/en-us/dotnet/standard/generics/covariance-and-contravariance 以下是Microsoft提供的有关此主题的更多信息: https//docs.microsoft.com/en-us/dotnet/standard/generics/covariance-and-contravariance

This is a pretty confusing example, but I believe the problem is you're casting to a generic type and giving it interfaces, when the classes your deriving from are forcing you to use DmModel and DbMode. 这是一个非常令人困惑的例子,但我相信问题是你正在转换为泛型类型并给它接口,当你派生的类强制你使用DmModel和DbMode时。

Perhaps this is what you meant: 也许这就是你的意思:

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

That compiles just fine, and I with that way your classes are structured, is the only option other than restructuring. 编译得很好,我用这种方式构建你的类,是重组之外的唯一选择。

Your interface IRule<in TInput, out TOutput> is both covariant and contravariant, which means you can't covariantly cast it. 你的界面IRule<in TInput, out TOutput>既是协变的又是逆变的,这意味着你无法共同演变它。 The contravariance prevents this. 逆变阻止了这种情况。

Basically, your assignment var dbModel = (IRule<IDmModel, IDbModel>)new RuleB(); 基本上,你的赋值var dbModel = (IRule<IDmModel, IDbModel>)new RuleB(); asserts that dbModel must accept any IDmModel parameter. 断言dbModel必须接受任何 IDmModel参数。 Unfortunately, this is not true; 不幸的是,事实并非如此; instances must be assignable to DmModel due to the concrete form of RuleA , so other derivatives of IDmModel would fail. 实例必须分配给DmModel由于的具体形式RuleA ,如此其它衍生物IDmModel会失败。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM