Вызов общего метода для нескольких статических классов? - PullRequest
0 голосов
/ 13 декабря 2018

Краткое примечание

Код в этом посте построен на основе встроенного DirectX-11 движка, что означает, что он следует строгому шаблону:

Initialize
while (Running) {
    Update
    Render
}

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


Обзор

У меня есть класс с именем RenderObject, который содержит метод с именем Initialize.Этот метод отвечает за построение сетки объекта, назначение текстур, шейдеров и т. Д.

public class RenderObject {
    public virtual void Initialize() { }
}

У меня также есть несколько классов static, которые содержат повторно используемые ресурсы, такие как обычные текстуры, шейдеры, модели исетки.Таким образом, мне не нужно перезагружать их позже.Все эти static классы также содержат метод, называемый Initialize, который отвечает за создание этих повторно используемых активов.Для этого вопроса я ограничу это только классом Textures.

public static class Textures {
    public static Texture2D Dirt { get; private set; }
    public static Texture2D Grass { get; private set; }
    public static void Initialize() {
        Dirt = new Texture2D(...);
        Grass = new Texture2D(...);
    }
}

Наконец, у меня есть класс с именем LoadingSystem, который отвечает за загрузку повторно используемых ресурсов и инициализацию объектов.Я инициализирую этот класс внутри метода Initialize моего движка, а затем вызываю метод класса 'Update в методе Update движка соответственно.Метод LoadingSystem Update отвечает за загрузку и инициализацию объектов с использованием Queue, что полезно для обеспечения плавной визуальной обратной связи.

 public class LoadingSystem {
     public bool Loading { get; private set; } = true;
     private Queue<RenderObject> objectsToRender;
     public void AddForLoad(RenderObject obj) => objectsToRender.Enqueue(obj);
     public void Update() {
         if (objectsToRender.Count > 0) {
             RenderObject obj = objectsToLoad.Dequeue();
             obj.Initialize();
         } else Loading = false;
     }
 }

Проблема

Я хотел бы вызвать метод Initialize для этих static классов с тем же процессом, который использовался для очереди RenderObject.В настоящее время я вынужден сделать:

CurrentMessage = "Loading Textures";
Render();
Present();
Textures.Initialize();
Progress = ++objectsLoaded / objectsToLoad;
CurrentMessage = "Loading Shaders";
Render();
Present();
Shaders.Initialize();
Progress = ++objectsLoaded / objectsToLoad;
CurrentMessage = "Loading Models";
Render();
Present();
Models.Initialize();
Progress = ++objectsLoaded / objectsToLoad;

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


Мои мысли

Я понимаю, что класс static не может наследоватьиз class или реализации interface, поэтому мне интересно, есть ли способ предоставить класс static и вызвать его метод Initialize аналогичным образом;даже если это означает создание отдельного метода для его выполнения.

В настоящее время я рассмотрел два варианта:

  • Загрузка статических классов по отдельности.
  • Преобразование статических классов в экземплярклассы и вызывать их с помощью очереди.

Проблема с первым вариантом состоит в том, что у меня есть 12 static классов, и мне придется обновлять сообщения о ходе выполнения и обратной связи, вызывать события и повторно отображатьсцена для каждого.

Проблема со вторым вариантом заключается в том, что эти static классы содержат только static свойства и, следовательно, по определению должны быть static, так как нет необходимости когда-либо наследовать от них илисоздайте их экземпляр.


Вопрос

Есть ли способ вызова общего метода для нескольких статических классов?

  • Возможно, способвызвать метод, если он существует с универсальными типами, такими как object или T?
  • Возможно, тип dynamic может работать (хотя вы не можете создать экземпляр static классов)?

Ответы [ 2 ]

0 голосов
/ 13 декабря 2018

В настоящее время я рассмотрел два варианта:

  • Загрузка статических классов по отдельности.
  • Преобразование статических классов в экземпляры классов и вызов их в очереди.

Третий компромиссный подход относится к вашей второй идее выше, но использует шаблон проектирования, известный как шаблон Singleton.Как и статические классы, в вашем процессе может быть только один из них, и каждый получает то же самое, однако в отличие от статических классов, Singletons могут реализовывать интерфейсы или даже переходить от других классов.

В этом примере я буду использоватьинтерфейсный подход.

public interface IInitializable
{
    void Initialize();
}

Все, что делает интерфейс - это обеспечивает, чтобы его разработчик имел метод Initialize.

Мой следующий шаг - создание класса Singleton.Есть несколько правил для реализации шаблона Singleton.Ваш класс должен быть запечатан.Его конструктор должен быть закрытым.Он должен иметь статический метод или свойство для возврата одного экземпляра.Этот метод / свойство должно быть потокобезопасным.

Я использовал Lazy для выполнения тяжелой работы за меня

public sealed class Foo : IInitializable
{
    public void Initialize()
    {
        // Initialize my foo
    }

    private Foo()
    {
    }

    private static Lazy<Foo> fooLazy = new Lazy<Foo>(() => new Foo());

    public static Foo Instance => fooLazy.Value;
}

Есть некоторые незначительные отличия от того, что вы делали со статическими классами.Если бы Foo был статическим классом, вы бы назвали Foo.Initialize(); Поскольку это Singleton, вы бы назвали Foo.Instance.Initialize();

Любые другие методы или свойства, скорее всего, были бы нестатичными.

Вытягиваниевсе вместе, вы можете написать код, как это.Ваша очередь не должна знать о классах, которые она содержит.Вам на самом деле все равно.Вы только хотите знать, что у него есть метод Initialize ()

   public class YourClass
    {
        private Queue<IInitializable> objectsToLoad = new Queue<IInitializable>();

        public void Enqueue(IInitializable obj)
        {
            this.objectsToLoad.Enqueue(obj);
        }

        public void LoadOrUpdate()
        {
            // Update Method
            if (objectsToLoad.Count > 0)
            {
                IInitializable obj = objectsToLoad.Dequeue();
                obj.Initialize();
            }
            else
            {
                // Loading complete.
            }
        }
    }

Этот класс может затем использоваться следующим образом

    YourClass yourClass = new YourClass();
    yourClass.Enqueue(Foo.Instance);
    yourClass.LoadOrUpdate();
0 голосов
/ 13 декабря 2018

Хотя я надеюсь, что есть гораздо лучший и более подробный ответ, чем этот;Я придумал базовое решение.Я создал отдельный Queue<Type>, где я добавляю static классы.Затем я вызываю их Initialize метод со следующим:

Type t = typesToInit.Dequeue();
t.GetMethod("Initialize").Invoke(null, new object[] { 0 });

Это хорошо работает и довольно чисто, но я не могу не задаться вопросом, есть ли лучший способ сделать это?

...