2015-12-11 177 views
1

我有一个泛型类型,它将成为事件系统中事件的基类。我们期望这些是单例,但它也是通用的,这样子类可以在事件触发时指定它们在回调中期望的参数的类型。在泛型Typescript类中实现单例

我有什么看起来像这样:

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

有在这里有些东西我觉得奇怪,并没有大多是因为打字稿语言要求。 GetInstance的参数似乎是必需的,因为var x = new TEvent()似乎不被TypeScript允许。空接口有助于实施可被接受为通用类型的内容。

这里似乎没有工作的是静态变量和泛型类型的组合。 GetInstance方法中的块是我想要做的,但显然它不能编译。我还担心静态实例变量不会为每个事件创建一次,而只是每个事件实例创建一次,并因此被覆盖。

任何指导在这里将不胜感激。

回答

1

在C#中,泛型类的每个实例(一组类型参数)都有自己的一组静态成员。这意味着您可以编写一个单例模式,其中您有一个实例为Foo<int>,另一个为Foo<string>,依此类推。这是可能的,因为泛型是清单在运行时 - 运行时系统实际上知道什么是泛型,并且可以为每个类型实例化分配新对象。此外,类的静态端可以引用该类的类型参数(这是运行时语义的结果)。

在TypeScript中,情况并非如此。每个类只有一个构造函数,泛型或其他。这意味着类的静态端不能“查看”通用类型参数,因为对于具有静态成员y的任何类X<T>X.y只有一个运行时隙。

类的单例模式通常不适合TypeScript;见How to define Singleton in TypeScript。我想你有一些XY problem在这里,所以我不能推荐任何具体的替代方案,没有关于你的用例是什么(可能发布一个单独的问题)的更多信息。

此外,你应该从来没有在TypeScript中有空接口。类型进行比较结构上,所以任何两个空的类型是兼容的,你可以分配任何东西到类型为空接口的变量。

+0

好吧,这就是我所关心的。我想我可能有一个替代实现的想法,会尝试,并可能发布一个单独的问题。谢谢! –

+0

对于具有不同名称和类型参数的派生类(通用单例的)是否也适用?我会假设这是作为独立的类来处理派生的。因此,当有一个通用版本时,每次需要一个独立的单例时,需要创建一个空的派生类,但可以重用通用单例代码。并不是说只有好奇才能做到这一点。 – ntziolis