4

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;
}
Shrembo
  • 833
  • 1
  • 8
  • 27

1 Answers1

4

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;
    }

}
G.Y
  • 6,042
  • 2
  • 37
  • 54
  • `if (person.PersonType.IsGood)` doesn't make sense then. – Pavel Anikhouski Feb 01 '20 at 10:10
  • @PavelAnikhouski, I agree, I didn't focus on what the method do inside, usually people hide the entire content of their methods implementations, just on the passages between the types. fixed – G.Y Feb 01 '20 at 10:35
  • `where T: Person` solve the method calling issue, okay. but what is the benefit of that since I can't use the derived classes `(GoodPerson)person.PersonType` – Shrembo Feb 01 '20 at 10:45
  • I'm not sure what you mean, you already passing GoodPerson, it was instantiated already from your calling code. your reflector just meant to interrogate on the properties - is it not what you wanted? – G.Y Feb 01 '20 at 11:04
  • @Shrembo I have add another answer - it is not an answer to the question - but I think this is what you really wanted to do. (If I may recommend - you should read about the Strategy Design Pattern) – G.Y Feb 01 '20 at 11:51
  • this the part I were locking for "Since Case is not the same type as Case" – Shrembo Feb 01 '20 at 13:37
  • 1
    @shrembo understood, but It ok, it is still good info for others who stumble the same area – G.Y Feb 01 '20 at 13:41