Невозможно получить доступ к методам подкласса объекта в словаре

Я пытаюсь хранить объекты, которые являются только подклассом абстрактного класса. Однако я могу видеть только методы абстрактного класса и ни один из методов подкласса. Что я пропустил?

Класс с ошибкой в:

class CharacterStats
{
    private Dictionary<StatType, Stat> playerStats;

    //Contructor for new game
    public CharacterStats()
    {

        playerStats = new Dictionary<StatType, Stat>();

        //Creates all Stats with default values
        playerStats.Add(StatType.STA, new StatSta());
        playerStats.Add(StatType.STR, new StatStr());
        playerStats.Add(StatType.DEX, new StatDex());
        playerStats.Add(StatType.DEF, new StatDef());

    }

    //Returns the damage reduction in %
    public int GetDamageReduction()
    {
        playerStats[StatType.DEF].  //Missing Methods from StatDef class
        //Added to remove error message
        return 1;
    }
}

Абстрактный класс:

 abstract class Stat
 {
    protected int pointsAdded;
    protected int pointCap;

    public Stat() {}

    public string TestMethod()
    {
        return "Working!";
    }

 }

Подкласс:

class StatDef : Stat
{

    public StatDef() : base()
    {
        this.pointsAdded = 0;
        this.pointCap = 100;
    }

    public int ApplyDamageReduction(int dmg)
    {
        //removed data to read easier
        return 1;
    }
}

Спасибо

Ваш словарь набирается на Stat, а не на подкласс. Компилятор не знает, каким может быть фактический подкласс во время выполнения, поэтому вы должны сначала преобразовать его в подкласс самостоятельно - при условии, что вы знаете, что это за подкласс.

Dai 02.05.2018 08:12

@ Дай, это должен быть ответ

Daniel Hilgarth 02.05.2018 08:12
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
2
52
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Тип экспрессии playerStats[StatType.DEF] - это просто Stat. Компилятор не знает, какой тип Stat хранится там в качестве значения.

Если всегда будет StatDef, вам нужно просто выполнить приведение:

var def = (StatDef) playerStats[StatType.DEF];
// Now you can use def.ApplyDamageReduction etc

Однако вам нужно будет использовать любой, когда вы хотите использовать член, зависящий от статистики. Если вы часто не хотите обрабатывать несколько статистических данных одинаково, я бы предложил отказаться от словарного подхода и просто использовать отдельные поля:

class CharacterStats
{
    private StatDefence defence;
    private StatAttack attack;
    private StatStrength strength;
    // etc
}

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

public IReadOnlyList<Stat> GetAllStats() =>
    new Stat[] { defence, attack, strength, ... };

Но я подозреваю, что наиболее, когда вы используете статистику, вы действительно хотите знать конкретную статистику. Я всегда лучше напишу:

var strength = stats.Attack;

чем

var strength = stats[StatType.STR];

даже если при не мне нужны конкретные аспекты статистики прочности.

Я планировал вычислить несколько разных значений в каждой статистике, таких как уменьшение урона, а также сохранить количество очков в каждом и общее допустимое количество очков. Возможно ли, чтобы значение словаря было подклассом, поскольку это работало бы очень хорошо, если бы я мог сделать это или что-то подобное. Еще одна причина, по которой я хотел использовать словарь, заключалась в том, что в будущем я собирался включить больше статистики и подумал, что это хороший способ сгруппировать все эти объекты.

Hamish Kendall 02.05.2018 08:30

@HamishKendall: значение уже является ссылкой на экземпляр подкласса. Но вы не должны ожидать, что тип во время компиляции результата поиска в словаре будет «типом, который вы хотите, чтобы он был» - это тип, который вы указали как второй аргумент типа для Dictionary<,>. Да, вы, безусловно, можете иметь общность в своем абстрактном базовом классе, но я все еще не уверен, что словарь - лучший способ приблизиться к этому. У вас есть определенный набор ключей, и вы знаете тип результата для каждого ключа, поэтому для меня это больше похоже на набор полей.

Jon Skeet 02.05.2018 08:34

Другие вопросы по теме