-1

I am trying to cast from a child with a specific generic to a parent with a more general generic.

Take the following code:

public class AParent { }
public class AChild : AParent { }

public interface IParent<T>
{
    public void func(T input);
}

public class Child : IParent<AChild>
{
    public void func(AChild input) { }
}

public static void test()
{
    IParent<AParent> parent = new Child();
}

In this code, I have AParent and AChild where AChild inherits from AParent.

I also have IParent which takes in a generic type parameter and Child which inherits from IParent with a specific type of AChild.

I feel like this should work logically? But I get the following error:

Cannot implicitly convert type 'Child' to 'IParent<AParent>'. An explicit conversion exists (are you missing a cast?)

I've also tried adding the in/out keyword to the T type parameter on IParent but to no avail. Is what I'm trying to do possible? It seems logical, what am I missing?

Montana
  • 482
  • 1
  • 4
  • 16
  • Hmm, maybe this is a simple answer and I just need an explicit cast – Montana Feb 06 '23 at 23:16
  • 1
    No, the explicit cast can only succeed if someone has written a class that implements _both_ `IParent` _and_ `IParent` which is not the case here. – Jeppe Stig Nielsen Feb 06 '23 at 23:30
  • 1
    `Child.func()` expects an instance of `AChild`. You can't cast an instance of `AParent` to a variable of `AChild`. Which means you can't cast the function, nor the interface. As this would allow you to break .net's type safety. – Jeremy Lakeman Feb 06 '23 at 23:50
  • @JeremyLakeman You're right. Thanks for pointing that out, that seems to be the piece I've overlooked. Thank you – Montana Feb 07 '23 at 00:08

1 Answers1

1

This generic interface:

public interface IParent<T>
{
    public void func(T input);
}

The type parameter T is used only as "input". So it would be legal to declare this a contravariant interface, like this:

public interface IParent<in T>
{
    public void func(T input);
}

This allows the opposite conversion of what you want:

IParent<AGrandchild> parent = new Child();

where AGrandchild is a class inheriting AChild.


Making the interface covariant ("out") would not be sound when there is an "in" use of T.

Jeppe Stig Nielsen
  • 60,409
  • 11
  • 110
  • 181