Inheriting generic can't up cast

2020-08-04 10:17发布

I have a problem with inheriting a custom generic. The compiler (Visual Studio for Mac), complaints that the inheriting generic can't be implicitly converted to another, inheriting type. A break down of my code is as follows:

I have an interface called IAnsweredCommon and another interface that inherits from it called IAnsweredAndroid

public interface IAnsweredCommon

and

public interface IAnsweredAndroid : IAnsweredCommon

I have two other classes that use these interfaces.

public abstract class ConstructorCommon<AnsweredType> where AnsweredType : IAnsweredCommon

and

public class ConstructorAndroid : ConstructorCommon<IAnsweredAndroid>

This works. The common constructor has a member variable of AnsweredType allowing it to treat it as IAnsweredCommon and run OS agnostic code against it, while allowing the Android constructor access to the same member variable and can treat it as IAnsweredAndroid allowing the Android constructor to run Android specific code against it. The Android constructor can handle Android specific things while passing OS agnostic code to the common constructor. This works and is what I want as it allows me to extend this to iOS.

Now the problem is that I have another layer on top of the constructor. The constructor basically implements the builder design pattern and so it has lots of methods to call in order to construct an answered object. I have director classes that call predetermined constructor methods to create a predetermined answered object.

public abstract class DirectorCommon<AnsweredConstructorType>
    where AnsweredConstructorType : ConstructorCommon<IAnsweredCommon>

and

  public class DirectorAndroid : DirectorCommon<ConstructorAndroid>

The compiler complains about being unable to implicitly convert ConstructorAndroid to ConstructorCommon<\IAnsweredCommon>. I've expanded upon ConstructorAndroid for testing purposes and I've temporary changed it to be:

public class DirectorAndroid : DirectorCommon<ConstructorCommon<IAnsweredAndroid>>

Now, if I change the IAnsweredAndroid interface to IAnsweredCommon, the error goes away (as it should since it exactly matches the constraint). But if I change it to IAnsweredAndroid, I get the error. I'm confused as IAnsweredAndroid IS IAnsweredCommon (inheritance) and therefore, the compiler should be able to upcast IAnsweredAndroid to IAnsweredCommon. After all it's doing this in the constructor classes.

NOTE: I've cleaned up the code to make it easier to read (removed namespaces, irrelevant code and what-not) so the code maybe not be 'runnable', but regardless, please point out any errors and I'm sure it's a minor thing I'm missing and you never know if an error is because of the clean up or if it's an actual error.

1条回答
你好瞎i
2楼-- · 2020-08-04 10:26

That is not possible, class<A> is not assignable to class<B>, also if A derives from B or vice versa.

It would work, if ConstructorCommon would be an interface, IConstructorCommon, and be defined as:

interface IConstructorCommon<out AnsweredType> where AnsweredType : IAnsweredCommon

The "out" makes it covariant.

To replace an abstract base-type with an interface, might be suitable.`

Your error has nothing to do with the constraint, the way you found just matches, cause the type matches. You can assign a ConstructorComman<Android> to ConstructorCommon<Android> but not to ConstructorCommon<Answer> no matter if there is a constraint or not. Constraints you need only if you want to call special methods, that only your constrained-type has.

查看更多
登录 后发表回答