Cannot pass a generic type object to a C # common interface

I have two interfaces:

public interface IDbModel {} public interface IDmModel {} 

And the classes derived from this:

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

I also 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 that, 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

And when I try to pass an object RuleB in IRule<IDmModel, IDbModel> occours unhandled exception

Cannot pass an object of type "ParsreCombinators.RuleB" to enter "ParsreCombinators.IRule`2 [ParsreCombinators.IDmModel, ParsreCombinators.IDbModel]".

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

What happened to this

To make the example less confusing, I simplify it:

EDIT:

After the answers, I realized what the problem is 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 
+5
source share
3 answers

These are the many levels of indirection that you got there ...

Here's the problem:

 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>

This cannot be passed to IRule <IDmModel, IDbModel>. C # does not support this type of casting. For the same reason, you cannot do List<object> b = (List<object>)new List<string>(); (Gives "Cannot convert type" System.Collections.Generic.List <string> to System.Collections.Generic.List <object>.))

This is a problem with covariance.

Here's another piece of information from Microsoft on the topic: https://docs.microsoft.com/en-us/dotnet/standard/generics/covariance-and-contravariance

+7
source

This is a rather confusing example, but I think the problem is that you are executing a generic type and providing interfaces to it when the classes you get force you to use DmModel and DbMode.

Perhaps this is what you meant:

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

This compiles just fine, and I structured your classes this way; this is the only option other than restructuring.

+3
source

Your IRule<in TInput, out TOutput> interface is covariant and contravariant, which means that you cannot discard it covariantly. Contravariance prevents this.

Basically, your purpose is var dbModel = (IRule<IDmModel, IDbModel>)new RuleB(); claims that dbModel must accept any IDmModel parameter. Unfortunately, this is not true; instances must be assigned to DmModel due to the specific form of RuleA , so other derivatives of IDmModel will not work.

+3
source

Source: https://habr.com/ru/post/1269611/


All Articles