跨多个静态 类 调用一个公共方法?
Calling a common method across multiple static classes?
快速说明
此 post 中的代码构建在内部构建的 DirectX-11
引擎之上,这意味着它遵循以下严格模式:
Initialize
while (Running) {
Update
Render
}
但是,不要让这吓到你,因为问题与 DirectX
代码无关,而是 static
classes 和方法。
概览
我有一个名为 RenderObject
的 class,其中包含一个名为 Initialize
的方法。此方法负责构建对象的网格、分配纹理、着色器等。
public class RenderObject {
public virtual void Initialize() { }
}
我还有一些 static
class 包含可重复使用的资产,例如常用纹理、着色器、模型和网格。这样我以后就不必重新加载它们了。所有这些 static
classes 还包含一个名为 Initialize
的方法,该方法负责创建这些可重用资产。对于这个问题,我将仅限于 Textures
class.
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
的class,它负责加载可重用资产和初始化对象。我在我引擎的Initialize
方法里面初始化这个class,然后在引擎的Update
方法中分别调用class'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;
}
}
问题
我想在这些 static
class 上使用与 RenderObject
队列相同的进程调用方法 Initialize
。目前我被迫做:
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 不能从 class
继承或实现 interface
所以我想知道是否有办法提供 static
class 并以类似的方式调用其 Initialize
方法;即使这意味着创建一个单独的方法来完成它。
我目前考虑了两个方案:
- 单独加载静态 classes。
- 将静态 classes 转换为实例 classes 并使用队列调用它们。
第一个选项的问题是我有 12 static
classes 并且必须更新进度和反馈消息、引发事件并为每个重新渲染场景。
第二个选项的问题是这些 static
classes 只包含 static
属性,因此根据定义应该是 static
因为没有必要曾经继承它们或创建它们的实例。
问题
有没有办法跨多个静态 classes 调用通用方法?
- 如果方法存在于
object
或 T
等泛型类型中,也许是一种调用方法的方法?
- 也许
dynamic
类型可以工作(尽管您不能创建 static
classes 的实例)?
虽然我希望有比这更好更详细的答案;我想出了一个基本的解决方案。我创建了一个单独的 Queue<Type>
,并在其中添加了 static
类。然后,我使用以下内容调用他们的 Initialize
方法:
Type t = typesToInit.Dequeue();
t.GetMethod("Initialize").Invoke(null, new object[] { 0 });
这很好用而且很干净,但我不禁想知道是否有更好的方法来做到这一点?
I have currently considered two options:
- Load static classes individually.
- Convert static classes to instance classes and call them with the queue.
第三种折衷方法与您上面的第二个想法相关,但使用称为单例模式的设计模式。与静态 classes 一样,您的进程中只能有一个,每个人都得到同样的东西,但是与静态 classes 不同的是,单例可以实现接口,甚至可以继承其他 class es.
对于这个例子,我将使用接口方法。
public interface IInitializable
{
void Initialize();
}
接口所做的只是强制其实现者具有 Initialize 方法。
我的下一步是创建一个 Singleton class。有几个规则可以实现单例模式。你的class必须封印。它的构造函数必须是私有的。它必须有一个静态方法或 属性 到 return 单个实例。 method/property 必须是线程安全的。
我已经使用 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;
}
与您使用静态 classes 所做的事情有一些细微差别。如果 Foo 是静态的 class,你会调用 Foo.Initialize();
因为它是 Singleton,你会调用 Foo.Instance.Initialize();
任何其他方法或属性很可能是非静态的。
综合起来,您可以编写这样的代码。您的队列不需要知道它持有的 classes。你其实并不在乎。你只想知道它有 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.
}
}
}
这个class可以这样使用
YourClass yourClass = new YourClass();
yourClass.Enqueue(Foo.Instance);
yourClass.LoadOrUpdate();
快速说明
此 post 中的代码构建在内部构建的 DirectX-11
引擎之上,这意味着它遵循以下严格模式:
Initialize
while (Running) {
Update
Render
}
但是,不要让这吓到你,因为问题与 DirectX
代码无关,而是 static
classes 和方法。
概览
我有一个名为 RenderObject
的 class,其中包含一个名为 Initialize
的方法。此方法负责构建对象的网格、分配纹理、着色器等。
public class RenderObject {
public virtual void Initialize() { }
}
我还有一些 static
class 包含可重复使用的资产,例如常用纹理、着色器、模型和网格。这样我以后就不必重新加载它们了。所有这些 static
classes 还包含一个名为 Initialize
的方法,该方法负责创建这些可重用资产。对于这个问题,我将仅限于 Textures
class.
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
的class,它负责加载可重用资产和初始化对象。我在我引擎的Initialize
方法里面初始化这个class,然后在引擎的Update
方法中分别调用class'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;
}
}
问题
我想在这些 static
class 上使用与 RenderObject
队列相同的进程调用方法 Initialize
。目前我被迫做:
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 不能从 class
继承或实现 interface
所以我想知道是否有办法提供 static
class 并以类似的方式调用其 Initialize
方法;即使这意味着创建一个单独的方法来完成它。
我目前考虑了两个方案:
- 单独加载静态 classes。
- 将静态 classes 转换为实例 classes 并使用队列调用它们。
第一个选项的问题是我有 12 static
classes 并且必须更新进度和反馈消息、引发事件并为每个重新渲染场景。
第二个选项的问题是这些 static
classes 只包含 static
属性,因此根据定义应该是 static
因为没有必要曾经继承它们或创建它们的实例。
问题
有没有办法跨多个静态 classes 调用通用方法?
- 如果方法存在于
object
或T
等泛型类型中,也许是一种调用方法的方法? - 也许
dynamic
类型可以工作(尽管您不能创建static
classes 的实例)?
虽然我希望有比这更好更详细的答案;我想出了一个基本的解决方案。我创建了一个单独的 Queue<Type>
,并在其中添加了 static
类。然后,我使用以下内容调用他们的 Initialize
方法:
Type t = typesToInit.Dequeue();
t.GetMethod("Initialize").Invoke(null, new object[] { 0 });
这很好用而且很干净,但我不禁想知道是否有更好的方法来做到这一点?
I have currently considered two options:
- Load static classes individually.
- Convert static classes to instance classes and call them with the queue.
第三种折衷方法与您上面的第二个想法相关,但使用称为单例模式的设计模式。与静态 classes 一样,您的进程中只能有一个,每个人都得到同样的东西,但是与静态 classes 不同的是,单例可以实现接口,甚至可以继承其他 class es.
对于这个例子,我将使用接口方法。
public interface IInitializable
{
void Initialize();
}
接口所做的只是强制其实现者具有 Initialize 方法。
我的下一步是创建一个 Singleton class。有几个规则可以实现单例模式。你的class必须封印。它的构造函数必须是私有的。它必须有一个静态方法或 属性 到 return 单个实例。 method/property 必须是线程安全的。
我已经使用 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;
}
与您使用静态 classes 所做的事情有一些细微差别。如果 Foo 是静态的 class,你会调用 Foo.Initialize();
因为它是 Singleton,你会调用 Foo.Instance.Initialize();
任何其他方法或属性很可能是非静态的。
综合起来,您可以编写这样的代码。您的队列不需要知道它持有的 classes。你其实并不在乎。你只想知道它有 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.
}
}
}
这个class可以这样使用
YourClass yourClass = new YourClass();
yourClass.Enqueue(Foo.Instance);
yourClass.LoadOrUpdate();