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

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

У меня есть функция, которая внутренне использует класс 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?

🤔 А знаете ли вы, что...
С C# можно разрабатывать веб-приложения с использованием ASP.NET и ASP.NET Core.


50
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);
}

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

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

    public override float DeltaTime => deltaTime;
}

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