Как я могу читать статические свойства из экземпляров классов?

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

У меня есть функция, которая внутренне использует класс Time и его свойства, как, например, deltaTime.

Чтобы отладить свою функцию, я хотел бы использовать не класс Time как есть, а его производный класс TimeDebug : Time и переопределить свойство deltaTime, превратив его во что-то предсказуемое, т.е.:

public class TimeDebug : Time
{
    public static new float deltaTime { get { return 0.2f; } }
}

Моя функция будет использовать класс как полиморфный параметр:

void DoSomething(TimeDebug timer)
{
...
...
}

Моя функция может получить параметр Time или TimeDebug, в зависимости от «Режима выпуска» или «Режима отладки»:

DoSomething(new TimerDebug())   // debug mode

DoSomething(new Timer())   // release mode

Теперь возникает вопрос: компилятор не позволит мне скомпилировать доступ для чтения к статическому члену deltaTime, потому что я делаю это из экземпляра класса. Например, я не могу сделать:

void DoSomething(TimeDebug timer)
{
Debug.Log(timer.deltaTime);   // won't compile!!
}

Как передать параметр класса, чтобы я мог прочитать свойство deltaTime, независимо от того, равен ли параметр класса Time или TimeDebug?

Какой смысл передавать экземпляр класса только для того, чтобы получить от него статическое свойство? Почему бы просто не передать сам deltaTime? release ? Time.deltaTime : 0.2f?

ipodtouch0218 30.07.2024 21:26

Это звучит как проблема XY. Какова основная цель, которая в первую очередь привела к созданию этого дизайна? Если цель состоит в том, чтобы иметь разные функциональные возможности в режиме отладки, то могут быть варианты получше.

David 30.07.2024 21:30

Другие уже упомянули фундаментальный недостаток этого подхода, поэтому я не буду туда углубляться. Я также видел упоминание об использовании Time.captureDeltaTime, хотя, возможно, вас тоже заинтересует Application.targetFrameRate, если вашей целью является тестирование с заданной частотой кадров.

Ryan Gray 31.07.2024 09:43

@ ipodtouch0218 Я пытался избежать ветвления кода, независимо от того, предварительно скомпилирован он или нет (@David). Наличие веток кода для каждого «исключения» показалось мне беспорядочным. Я думал, что наследование могло бы добавить больше простоты, потому что мы используем один и тот же код функции (без ветвления), работающий с обоими классами, благодаря полиморфизму. Возможно, полиморфизм нецелесообразен?

oscar 31.07.2024 15:32

Вы не можете переопределить статическое свойство, поскольку статические свойства не могут быть virtual. Лучшее, что вы можете сделать, это создать новый класс, который имеет собственное нестатическое свойство virtual float deltaTime, и создать два дочерних класса, которые наследуются от него: один возвращает Time.deltaTime, а другой возвращает 0.2f; затем пройдите эти занятия.

ipodtouch0218 31.07.2024 15:38

@ ipodtouch0218 Я думаю, что твое решение - точное решение вопроса. Мне жаль, что я этого не понял... :-) Не могли бы вы отредактировать свой ответ ниже и добавить к нему свои недавние слова комментария? Тогда я отмечу задачу как решенную.

oscar 31.07.2024 18:45

@oscar сделал это.

ipodtouch0218 31.07.2024 18:49
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
7
50
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

Я чувствую, что это проблема XY. На самом деле вас не волнует «получение статического свойства через экземпляр», вы пытаетесь исправить deltaTime до определенного значения в Unity (условно).

Это можно сделать, просто установив для Time.captureDeltaTime значение 0,2f:

Если это свойство имеет ненулевое значение, то Time.time увеличивается с интервалом captureDeltaTime (масштабируемым Time.timeScale) независимо от реального времени и продолжительности кадра. Это полезно, если вы хотите снять фильм, в котором вам нужна постоянная частота кадров и вы хотите оставить достаточно времени между кадрами для сохранения изображений на экране.

Очевидно, что из-за того, что вы блокируете deltaTime без блокировки частоты кадров, игра будет работать СЛИШКОМ быстро для большинства компьютеров. (1 секунда реального времени при 200 кадрах в секунду будет 0.2 (deltaTime) * 200 (frames) = 40 секундам игрового времени)

Что касается того, почему это называется «captureDeltaTime»; он предназначен в основном для «захвата» видео игрового процесса как можно быстрее, без учета того, как оно выглядит в реальном времени. Похоже на то, что видеоредакторы при рендеринге просматривают видео намного быстрее, чем в реальном времени.


Решение «Y»-части проблемы XY: вы не можете переопределить статическое свойство, поскольку статические свойства не могут быть виртуальными.

Лучшее, что вы можете сделать, это создать новый класс, который имеет собственное нестатическое свойство virtual float deltaTime, и создать два дочерних класса, которые наследуются от него: один возвращает Time.deltaTime, а другой возвращает 0.2f; затем перейдите в эти классы:

public class Timer {
  public virtual float deltaTime => Time.deltaTime;
}

public class DebugTimer : Timer {
  public override float deltaTime => 0.2f;
}

Затем вы можете просто передать экземпляр Timer:

void DoSomething(Timer timer)
{
    Debug.Log(timer.deltaTime);
}

Действительно хороший хак, не знал об этом. Однако, поскольку я только тестирую функцию, ее вызовы происходят только внутри одного кадра. Почему? Потому что таким образом мне не придется ждать (например) 10000 кадров, чтобы протестировать 10000 вызовов функций. Выполнение 10000 вызовов функций внутри простого цикла for (все внутри одного кадра) намного эффективнее. А мой класс TimeDebug был предназначен для имитации разного времени кадра (и других параметров) при каждом вызове без выхода из кадра. Так что да, это похоже на проблему XY... но я подумал, что наследование может быть элегантным решением этой ситуации.

oscar 31.07.2024 14:57

Обобщенным решением было бы предоставить Time(r) (какой из них?) виртуальное нестатическое свойство, которое может быть переопределено производным классом:

public class TimeDebug : Time
{
    public static new float deltaTime { get { return 0.2f; } }

    public override float DeltaTime => deltaTime;
}

Использование соглашений об именах для указания обоих видов доступа может вызывать опасения (может быть даже сомнительно вообще иметь статическое свойство, в зависимости от вашего использования), но это «правильный» способ запроса свойства, привязанного к конкретному экземпляр класса, который будет запрошен методами. Другие, более загадочные реализации могут включать в себя предоставление таймеру обобщенного свойства DeltaTime, которое использует отражение ссылки «this» для поиска фактического значения статического свойства «deltaTime», но я не думаю, что здесь это имеет большой смысл.

Если вы ссылаетесь на него, полное квалифицированное имя класса «Time» — это класс «UnityEngine.Time». Что касается вашего ответа, свойство «DeltaTime» будет новым и не будет существовать в базовом классе «Time», AFAIK, поэтому полиморфизм потерпит неудачу, не так ли? Если нам нужно написать две разные функции для доступа к каждому классу, мы теряем преимущества наследования.

oscar 31.07.2024 14:17

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