Как получить объект дочернего класса из списка базовых классов? - PullRequest
0 голосов
/ 31 октября 2018

Рассмотрим пример иерархии

class BaseClass{}

class ChildClass1 : BaseClass{}

class ChildClass2 : BaseClass{}

Теперь у меня есть общий список типа BaseClass

List<BaseClass> sampleList = new List<BaseClass>();

И в этот список я добавляю объекты обоих ChildClass1 и ChildClass2.

Теперь, когда я получаю доступ к этим объектам, я хочу выполнять разные операции для разных типов объектов. Я могу легко добиться этого, используя if-else и проверяя, имеет ли объект требуемый тип.

 class SampleClass
 {
     int Property{get;set;}
     List<BaseClass> sampleList = new List<BaseClass>();
     void DoCalculations()
     {
        foreach(var obj in sampleList)
        {
            if(obj is ChildClass1){//Do something to this.Property}
            else if(obj is ChildClass2){//Do Somethingto this.Property}
         }
     }
 }

Однако из-за сложности и проблем с производительностью я хотел избежать if-else или switch (Мой реальный случай содержит огромное количество производных классов).

Итак, чтобы обойти это условие, я предложил подход с перегрузкой методов с одинаковыми именами, но разными типами (каждый для каждого производного типа).

Я думал о том, чтобы как-то итерировать и приводить BaseClass к объектам ChlidClass и передавать его в метод DoSomething(), а перегрузка сама позаботится о том, какую операцию выполнить. Однако я не могу получить объект типа ChildClass из BaseClass для динамической работы.

То, что я пробовал, это:

class SampleClass
{
    int Property{get;set;}
    List<BaseClass> sampleList = new List<BaseClass>();

    public void DoCalculations()
    {
        foreach(var entry in sampleList)
        {
            Type type = entry.GetType();
            var obj = entry as type; //getting error here
            this.DoSomething(obj);
        }
    }

    private void DoSomething(ChildClass1 obj){//Do something to this.Property}

    private void DoSomething(ChildClass2 obj){//Do something to this.Property}
}

В приведенном выше коде я показал только использование одного свойства int Property{get;set;}, но в моем реальном случае рассмотрим более одного свойства в игре. Есть ли способ добиться того, что мне нужно?

Редактировать: Как упомянуто в комментариях ниже и в нескольких ответах есть метод DoSomething () в BaseClass () и переопределяющий их в ChildClasses, который может на самом деле не работать в моем случае, так как DoSomething () работает со свойствами глобальных полей класса, который он определен в . Это не относится к объекту ChildClass.

Ответы [ 2 ]

0 голосов
/ 31 октября 2018

Вы должны сделать DoSomething виртуальным методом в BaseClass и позволить производным классам переопределить его соответствующим образом. Тогда вы можете просто позвонить DoSomething на любой экземпляр, который у вас есть:

class BaseClass
{
    virtual void DoSomething() { ... }
}
class Child1 : BaseClass
{
    override void DoSomething() { Console.WriteLine("Child1"); }
}

Теперь вам не нужно проверять тип, так как экземпляр знает его тип и, следовательно, среда выполнения знает, какое переопределение вызывать:

foreach(BaseClass obj in sampleList)
{
    obj.DoSomething();
}

Вы можете даже сделать свой DoSomething -метод abstract, если хотите заставить производные классы реализовать его. ИМХО это имеет смысл, если только вы не хотите иметь возможность создавать экземпляр BaseClass.

0 голосов
/ 31 октября 2018

Подумайте о создании класса BaseClass abstract и задайте ему метод abstract. Оба типа ChildClass1 и ChildClass2 будут вынуждены переопределить DoSomething()

Если по какой-то причине вы не можете сделать BaseClass абстрактным, вы можете также сделать метод virtual, а затем override в ChildClass1 и ChildClass2

Абстрактный подход:

abstract class BaseClass
{    
    public abstract void DoSomething();
}

class ChildClass1 : BaseClass{
    public override void DoSomething()
    {
        Console.WriteLine("Impl. 1");
    }
}

class ChildClass2 : BaseClass{

    private string _someRandomAttribute = "Impl. 2";
    public override void DoSomething()
    {
        Console.WriteLine(_someRandomAttribute);
    }
}

Виртуальный подход:

class BaseClass
{    
    public virtual void DoSomething()
    {
       Console.WriteLine("Base implementation for types that don't override DoSomething()");
    }
}

class ChildClass1 : BaseClass{
    public override void DoSomething()
    {
        Console.WriteLine("Impl. for type ChildClass1");
    }
}

class ChildClass2 : BaseClass{
    public override void DoSomething()
    {
        Console.WriteLine("Impl. for type ChildClass2");
    }
}

После того, как вы закончите с этим, вы сможете сделать следующее:

foreach(var obj in sampleList)
{
    obj.DoSomething();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...