David
David

Reputation: 87

Polymorphism, inheritance and generic C# : Cannot cast subclass into supertype

I have a problem with abstract class and generic in c# (I usually code in Java) : here is the code I would like to use :

public interface InterfaceResult {...}

public abstract class Result : InterfaceResult {...}   
public class ResultA : Result {...}
public class ResultB : Result {...}

public interface InterfaceKing { InterfaceResult function();}

public abstract class King : InterfaceKing {
  public abstract Result function();
}
public class KingA : King {
  public override ResultA function(){...}
}
public class KingB : King {
  public override ResultB function(){...}
}

but that doesn t work : Visual Studio want for KingA and KingB to return an instance of Result with function(). If i use "new" instead of override, VS say I don t implement the required method (i need to use override).

So I tried with generic and it s not better

public abstract class Result    {    }
public class ResultA : Result    {    }
public class ResultB : Result    {    }

public interface IKing<T>    {T function();    }

public abstract class King<Result> : IKing<Result>
{
    public abstract Result function();

    public static implicit operator King<Result>(KingB v)
    {
        return v; // generate StackOverflow Exception
    }

    public static implicit operator King<Result>(KingA v)
    {
        throw new NotImplementedException();
    }
}

public class KingA : King<ResultA>
{
    public override ResultA Get()
    {
        return new ResultA();
    }
}

public class KingB : King<ResultB>
{
    public override ResultB Get()
    {
        return new ResultB();
    }
}

public class Test
{
    King<Result> a = new KingA(); // allowed by  public static implicit operator King<Result>(KingA v)
    King<Result> b = new KingB(); // allowed by  public static implicit operator King<Result>(KingB v)
    KingA ka = new KingA();
    List<King<Result>> lista = new List<King<Result>>();
    public void test()
    {
        lista.Add(ka);
    }        
}

How can i make this work ? I can t find any solution nor any good or complete example.

Upvotes: 0

Views: 287

Answers (2)

Michael
Michael

Reputation: 3631

Using covariance

See .net fiddler here. Read more about Covariance and Contravariance

public abstract class Result { }

public class ResultA : Result { }

public class ResultB : Result { }

public interface IKing<out T> where T : Result {}

public abstract class King<T> : IKing<T> where T : Result
{
    public abstract T Get();
}

public class KingA : King<ResultA>
{
    public override ResultA Get()
    {
        return new ResultA();
    }
}

public class KingB : King<ResultB>
{
    public override ResultB Get()
    {
        return new ResultB();
    }
}

public class TestClass
{
    King<ResultA> a = new KingA(); // allowed by  public static implicit operator King<Result>(KingA v)
    King<ResultB> b = new KingB(); // allowed by  public static implicit operator King<Result>(KingB v)
    KingA ka = new KingA();
    List<IKing<Result>> lista = new List<IKing<Result>>();

    public void Test()
    {
        lista.Add(ka);
    }        
}

Upvotes: 0

Sehnsucht
Sehnsucht

Reputation: 5049

Moving from "full interface" to "no interface" (for lack of better terms) all that work (this Main works fine)

static void Main ()
{
    King a = new KingA ();
    King b = new KingB ();
    KingA ka = new KingA ();
    List<King> list = new List<King> ();

    list.Add (a);
    list.Add (b);
    list.Add (ka);
}

"full interface"

    public interface InterfaceResult { }

    public abstract class Result : InterfaceResult { }
    public class ResultA : Result { }
    public class ResultB : Result { }

    public interface InterfaceKing { InterfaceResult Function (); }

    public abstract class King : InterfaceKing
    {
        public abstract InterfaceResult Function ();
    }
    public class KingA : King
    {
        public override InterfaceResult Function () => new ResultA ();
    }
    public class KingB : King
    {
        public override InterfaceResult Function () => new ResultA ();
    }

"mixed (less interface)"

    public abstract class Result { }
    public class ResultA : Result { }
    public class ResultB : Result { }

    public interface IKing { Result Function (); }

    public abstract class King : IKing
    {
        public abstract Result Function ();
    }

    public class KingA : King
    {
        public override Result Function () => new ResultA ();
    }

    public class KingB : King
    {
        public override Result Function () => new ResultB ();
        {
            return new ResultB ();
        }
    }

"no interface"

    public abstract class Result { }
    public class ResultA : Result { }
    public class ResultB : Result { }

    public abstract class King
    {
        public abstract Result Function ();
    }

    public class KingA : King
    {
        public override Result Function () => new ResultA ();
    }

    public class KingB : King
    {
        public override Result Function () => new ResultB ();
    }

Upvotes: 1

Related Questions