C# - необходимо вызвать функцию переопределения дочерних элементов, когда «знает» только родительский элемент - PullRequest
1 голос
/ 19 июня 2020

У меня есть эти классы в игре (упрощенно):

public class GameUnit
{
    public enum UnitType
    {
        FighterUnit,
        MageUnit,
        Count,
    }

    public UnitType type;

    public virtual void OnUnitSelected()
    {
        HighlightUnit();
    }
}

public class FighterUnit : GameUnit
{
    public FighterUnit()
    {
        type = UnitType.FighterUnit;
    }

    public override void OnUnitSelected()
    {
        PlayFighterSound();
        base.OnUnitSelected();
    }

    public void Punch()
    {
        PunchInfrontOfMe();
    }
}

public class MageUnit : GameUnit
{
    public MageUnit()
    {
        type = UnitType.MageUnit;
    }

    public override void OnUnitSelected()
    {
        PlayMageSound();
        base.OnUnitSelected();
    }

    public void CastSpell()
    {
        CreateSpellAtPosition();
    }
}

Я сохраняю эти юниты в списке и могу создавать их и щелкать по ним следующим образом:

public class GameUnitController
{
    public List<GameUnit> units;
    public void SpawnUnit(GameUnit.UnitType type)
    {
        switch (type)
        {
            case GameUnit.UnitType.FighterUnit:
                FighterUnit newFighterUnit = new FighterUnit();
                units.Add(newFighterUnit);
                break;

            case GameUnit.UnitType.MageUnit:
                MageUnit newMageUnit = new MageUnit();
                units.Add(newMageUnit);
                break;
        }
    }

    public void UnitClicked(GameUnit unit)
    {
        unit.OnUnitSelected();
    }
}

Когда мне нужно, я могу преобразовать их в их дочерний класс, когда это необходимо для спецификации c logi c, например:

public void PerformAction(GameUnit unit)
    {
        switch (unit.type)
        {
            case GameUnit.UnitType.FighterUnit:
                ((FighterUnit)unit).Punch();
                break;

            case GameUnit.UnitType.MageUnit:
                ((MageUnit)unit).CastSpell();
                break;
        }
    }

Однако моя база кода уже начинает доходить до точка, где я добавляю множество операторов switch для типов классов, и мне нужен более простой способ обработки более общих c вызовов функций (см. проблему OnUnitSelected).

Текущая проблема с OnUnitSelected, это то, как это написано здесь, он вызывает OnUnitSelected родительского класса только тогда, когда я хочу, чтобы он go проходил через все из них.

Есть ли хороший способ использовать свое перечисление для создания чего-то общего c в базовом классе, который мог бы вернуть его как правильный класс и не должен go через множество операторов switch, которые будут становиться все больше и больше по мере добавления дополнительных единиц.

Любой совет - это много приблизительно ecated.

Спасибо!

РЕДАКТИРОВАТЬ: Решение, которое я выбрал в конце:

Отредактировал GameUnit как таковой:

public class GameUnit
{
    public enum UnitType
    {
        FighterUnit,
        MageUnit,
        Count,
    }

    public UnitType type;

    public virtual void OnUnitSelected()
    {
        HighlightUnit();
    }

    public virtual void RunMethod(Action method)
    {
        method();
    }

    public void DoAsChild(Action method)
    {
        switch (type)
        {
            case UnitType.FighterUnit:
                FighterUnit fighterUnit = (FighterUnit)this;
                fighterUnit.RunMethod(method);
                break;

            case UnitType.MageUnit:
                MageUnit mageUnit = (MageUnit)this;
                mageUnit.RunMethod(method);
                break;
        }
    }
}

И отредактировал производные классы для переопределения метода:

public class FighterUnit : GameUnit
{
    public FighterUnit()
    {
        type = UnitType.FighterUnit;
    }

    public override void OnUnitSelected()
    {
        PlayFighterSound();
        base.OnUnitSelected();
    }

    public void Punch()
    {
        PunchInfrontOfMe();
    }

    public override void RunMethod(Action method)
    {
        method();
    }
}

public class MageUnit : GameUnit
{
    public MageUnit()
    {
        type = UnitType.MageUnit;
    }

    public override void OnUnitSelected()
    {
        PlayMageSound();
        base.OnUnitSelected();
    }

    public void CastSpell()
    {
        CreateSpellAtPosition();
    }

    public override void RunMethod(Action method)
    {
        method();
    }
}

Итак, теперь, когда у меня есть переопределяемая функция, такая как OnUnitSelected, я могу вызвать родительский элемент, который, в свою очередь, приведет себя к правильному дочернему элементу и вызовет метод из детский класс:

public void UnitClicked(GameUnit unit)
{
    unit.DoAsChild(unit.OnUnitSelected);
}
...