我有一个泛型类型,它将成为Event系统中事件的基类。我们希望这些是单例,但它也是通用的,这样子类可以在事件触发时指定它们在回调中所期望的参数类型。
我看起来像这样:
export interface IEvent { }
export interfact IEventArg { }
export abstract class Event<TEvent extends IEvent, TEventArg extends IEventArg> implements IMessageHandler {
private static s_instance : any;
private static s_isInitializing : boolean;
constructor() {
if (!Event.s_isInitializing)
throw new Error ("Use the GetInstance method to get this class instance.");
}
public static GetInstance<TEvent extends IEvent, TEventArg extends IEventArg>(type: { new() : T; }) : TEvent {
if (!s_instance) {
s_isInitializing = true;
s_instance = new type();
s_isInitializing = false;
}
return s_instance;
}
}
export class SelectionEvent extends Event<SelectionEvent, EmptyEventArg> {
...
}
var event = SelectionEvent.GetInstance(SelectionEvent);
这里有一些我觉得奇怪的东西,主要是因为Typescript语言要求。 GetInstance的参数似乎是必要的,因为TypeScript似乎不允许var x = new TEvent()
。空接口有助于强制执行可以作为泛型类型接受的内容。
这里似乎不起作用的是静态变量和泛型类型的组合。 GetInstance方法中的块是我想要做的,但显然它不能编译。我还担心每个事件不会创建一次静态实例变量,而是每个事件实例只创建一次,因此会被覆盖。
非常感谢此处的任何指导。
答案 0 :(得分:2)
在C#中,泛型类的每个实例化(类型参数集)都有自己的一组静态成员。这意味着您可以编写单例模式,其中Foo<int>
有一个实例,Foo<string>
有另一个实例,依此类推。这是可能的,因为泛型在运行时是 manifest - 运行时系统实际上知道什么是泛型,并且可以为每个类型实例分配新对象。另外,类的静态方面可以引用该类的类型参数(这是运行时语义的结果)。
在TypeScript中,情况并非如此。每个类只有一个构造函数,通用或其他。这意味着班级的静态方面不能看到&#34;泛型类型参数,因为对于具有静态成员X<T>
的任何类y
,X.y
只有一个运行时槽。
类的单例模式通常不适合TypeScript;见How to define Singleton in TypeScript。我认为你有一些XY problem在这里,所以我不能推荐任何具体的替代方案,而没有更多关于你的用例是什么的信息(可能会发布一个单独的问题)。
此外,你应该永远在TypeScript中有空接口。类型比较结构,因此任何两个空类型都是兼容的,您可以将任何内容分配给键入为空接口的变量。