Есть ли способ обеспечить существование статического члена в дочернем классе в C #? - PullRequest
5 голосов
/ 22 декабря 2010

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

Поскольку стоимость типа плиток остается неизменной,Казалось бы, имеет смысл сделать это статичным.К сожалению, C #, похоже, не позволяет использовать абстрактные классы или интерфейсы для обеспечения существования такого статического поля в дочернем классе.

Моим «решением» было получить эти данные с помощью отражения, но, похоже,для меня довольно некрасиво и потенциально опасно, так как я мог бы забыть статическое поле в одном из дочерних классов, что могло бы разрушить все это…

Следующий фрагмент кода - это то, что у меня сейчас есть;AllowedUpdates - это List<System.Type>, содержащий типы, на которые можно обновить плитку.

foreach (Type t in AllowedUpdates) {

    // Get the Action Point Cost
    FieldInfo fi = t.GetField ("actionPointCost", BindingFlags.NonPublic | BindingFlags.Static);
    int cost = (int)fi.GetValue (null);

    // Check for any requirements
    bool requirementsFulfilled;
    try {
        // Get the static method that checks the necessary requirements.
        MethodInfo mi = t.GetMethod ("CheckRequirements", new Type[] { typeof(Dictionary<string, ProtoObject>) });
        object[] arguments = { neighbourFields };

        // Invoke this method
        object returnValue = mi.Invoke (null, arguments);
        requirementsFulfilled = (bool)returnValue;
    } catch (ArgumentNullException) {
        // This type has no special requirements, pass it.
        requirementsFulfilled = true;
    } catch (NullReferenceException) {
        // No requirements needed, pass it.
        requirementsFulfilled = true;
    }
}

Должен быть лучший способ сделать это.Есть ли шаблон дизайна, который я пропустил?

Ответы [ 5 ]

6 голосов
/ 22 декабря 2010

С помощью абстрактного базового класса или интерфейса нельзя принудительно установить существование члена static в любом производном классе.

Отражение не самая лучшая ставка здесь. В этом случае пересмотрите использование классов static. Вы можете сделать стоимость типа плитки доступной только для чтения. Производные классы будут вынуждены реализовать свойство.

public abstract int ActionPointCost { get; }
0 голосов
/ 22 декабря 2010

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

Я бы сказал, что если реализация становится грязной без какой-либо выгоды, кроме как "кажется, что должно", то дизайн ошибочен.

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

0 голосов
/ 22 декабря 2010

Нет. Interfaces и Abstract classes не позволяют вам применять это.

Причина в том, что они привязаны к экземплярам этих классов, а не к их определениям. * * * * * * * * * * * * * * * * * * * * * * * * * По этой теме есть хорошая запись от Eric Lippert, но сейчас я не могу найти эту ссылку.

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

Другим способом может быть использование действия после сборки для проверки этих ограничений, например Code Contracts do.

0 голосов
/ 22 декабря 2010

Рефакторинг метаданных о плитках в другую иерархию классов, где есть такие вещи, как стоимость и т. Д.

0 голосов
/ 22 декабря 2010

Нет, это невозможно. Вам нужно будет либо создать экземпляр экземпляра и использовать поле / свойство экземпляра (что может быть быстрее, чем отражение, которое вы сейчас делаете). Или вы можете сохранить Dictionary<Tile, int>, в котором хранится нужное вам значение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...