Shrembo
Shrembo

Reputation: 1021

C# generics with inheritance

My problem is for some reason, I can't use derived class as the base when I pass it through a generic.

Let's suppose the below code to describe the idea

public class Person
{
    public virtual bool IsGood { get; }
}
public class GoodPerson : Person
{
    public override bool IsGood { get; } = true;

}
public class BadPerson : Person
{
    public override bool IsGood { get; } = false;
}

public class Case<T>
{
    public T PersonType { get; set; }
}
public class TypeReflector
{
    public Person Reflect(Case<Person> person)
    {
        if (person.PersonType.IsGood)
            return (GoodPerson)person.PersonType;

        return (BadPerson)person.PersonType;
    }
}

and called as below:

        var reflector = new TypeReflector();
        var result = reflector.Reflect(new Case<GoodPerson>());

why the method Reflect can't be called with Case<GoodPerson>. but it possible without the Case as below:

public Person Reflect(Person person)
{
    if (person.IsGood)
        return (GoodPerson)person;

    return (BadPerson)person;
}

Upvotes: 4

Views: 169

Answers (1)

G.Y
G.Y

Reputation: 6159

Since Case<Person> is not the same type as Case<GoodPerson>
Much like..
Case<int> is not the same type like Case<string>

Your reflector expected a strong type Case<Person> but you're providing it a different strong type Case<GoodPerson> (so this is like providing Case<string> to a method which expects Case<int>)

To make it work, make your reflector accept Case where T is a person or derived class of a person like this:

public class TypeReflector
{
    public Person Reflect<T>(Case<T> person) where T:Person
    {
        return person.PersonType;
    }
}

But below is what I think you really want to achieve, getting an instance of a type based on properties supplied in descriptor type. A type Person once instantiated cannot be "elevated" to GoodPerson instance without another new keyword somewhere.. (btw, the opposite is possible, creating a GoodPerson and casting to the more basic Person class)

using System;

namespace ConsoleApp25
{
    class Program
    {
        static void Main(string[] args)
        {

            var personDescriptor = new PersonDescriptor { IsGood = true };

            var resultPerson = personDescriptor.CreateInstance();

            Console.WriteLine(resultPerson.IsGood);
            Console.WriteLine(resultPerson.GetType().Name);

            Console.ReadLine();
        }
    }

    public class PersonDescriptor
    {
        public bool IsGood { get; set; }

        public Person CreateInstance()
        {
            if (IsGood)
                return new GoodPerson(); //create new instance!
            return new BadPerson(); //create new instance!
        }
    }

    public abstract class Person
    {
        public abstract bool IsGood { get; }
    }

    public class GoodPerson : Person
    {
        public override bool IsGood { get; } = true;
    }

    public class BadPerson : Person
    {
        public override bool IsGood { get; } = false;
    }

}

Upvotes: 4

Related Questions