返回子类的单例实例

3

我有几个单例类,所以我尝试创建一个具有方法GetInstance(params)的父类BaseClass和派生类,它应该实现这个方法并返回自己的实例(所以我不必转换它们)......由于它们是单例的,因此该方法应该是静态的,但是不允许覆盖静态方法。最好的编码方法是什么?我想要的示例代码:

  public class Base {

    public static virtual T GetInstance<T>() where T : class;
  }


  public class Derived {
    Derived instance;

    public static override T GetInstance<T>() where T : typeOf(this){
      if (instance == null) {
        instance = new Derived();
        }
      return instance;
    }
  }

在这段代码之外,我想要调用...
Derived.GetInstance().SomeDerivedMethod()

(Derived.GetInstance() as Derived).SomeDerivedMethod() and not
new Derived().getInstance().SomeDerivedMethod()

我知道这并不好,而且我对类型T缺乏经验,所以欢迎任何建议。 谢谢
编辑: 或者如果可以在Base中定义GetInstance()方法,这样派生类就不需要覆盖它了,但它将返回从哪里调用的类的实例... Derived.GetInstance()将返回Derived的实例。

1
这个类应该有什么目的?使用IoC容器可能更合适。 - vgru
1
我将拥有更多的单例,因此我希望提取创建实例的逻辑,以便从父级继承的静态方法始终可以返回一个调用它的类型的实例(即使是从子类)。 - Zavael
1
这里有一个类似的讨论http://www.codeguru.com/forum/showthread.php?t=376943,看起来没有办法强制子类成为单例,好像我想要的是一些奇怪的东西.. :( - Zavael
4个回答

3
尝试使用抽象工厂设计模式。也许其他创建型设计模式也适用。
您需要在工厂级别上强制实现“单例模式”,然后调用可能如下所示:
FooFactory.GetBarInstance().SomeDerivedMethod();

@Zavael:这就是为什么它被称为抽象。如果你需要一个Foo,你使用一个Foo工厂。它可以实现一个通用接口,但每个工厂都实例化自己的类型。 - vgru

3
您可以使用一个Dictionary<Type, Object>来实现单例模式。下面的方法要求每个类型都实现了私有构造函数。当然,您也可以在每个派生类中进行检查,看看单例字典中是否已经存在该类的实例。这甚至可以避免使用Activator创建实例。 未经测试:
public class Base {
    static Dictionary<Type, Object> _Singletones = new Dictionary<Type, Object>();
    public static T GetInstance<T>() where T : class {
        Type t = typeof(T);
        if (_Singletones.ContainsKey(t))
             return _Singletones[t] as T;
        else {
            // Create instance by calling private constructor and return it
            T result = Activator.CreateInstance(t, true) as T;
            _Singletones.Add(t, result);
            return result;
        }
    }
}

这是可以的,尽管像这样的静态方法应该是线程安全的。 - vgru
1
是的,差不多了...但我该如何从调用类中获取类型而不是从参数中获取类型呢?所以,我应该调用Base.GetInstance()来返回Base和Derived.get..来返回Derived,而不是Base.GetInstance<Derived>() = Derived.GetInstance<Derived>()。 - Zavael
@Zavael 我认为这是不可能的。你需要使用 Base.GetInstance<Dervied>() 访问它。(在派生类中工作时不使用 base) - Felix K.
@Felix:不确定您所说的“交换”是什么意思。如果需要从不同的线程访问它,那么它应该是线程安全的,除非在启动时实例化了所有可能的值并且字典被用作只读(目前没有强制执行这一点)。 - vgru
@Zavael:那么你的方法不应该是静态的。使用一个基本的泛型类,其中包含一个实例方法,该方法使用一个静态字典。但很可能,如果你需要这个,你正在做一些错误的事情。 - vgru
显示剩余3条评论

2

这并不是一个真正的答案,但可能知道也很好。 懒惰


1
+1 感谢 lazysingleton1 的再次检查 :) Lambda 版本我无法使用,因为我有的是单例字典,而不是一个实例。 - Zavael

0
为什么不直接将方法声明为非泛型类型,直接使用派生类型呢:
public class Derived {
  Derived instance;

  public static Derived GetInstance() {
    if (instance == null) {
      instance = new Derived();
    }
    return instance;
  }
}

是的,这是一种方法。我想通过父类Base强制任何派生类实现单例方法GetInstance()。 - Zavael
1
你不能强制在C#中实现静态方法。 - Jonas Høgh
是的,我知道,这就是我为什么要寻求建议的原因,是否有可能实现我想要的目标 :) - Zavael
4
@Zavael - 这要看情况。使用静态方法实现单例模式的教科书实现是不可能的。但更好的确保单例的方法是使用控制反转(IoC),让容器来管理您的实例的生命周期。在大多数框架中,声明所有给定类的子类具有单例生存期应该很简单。 - Jonas Høgh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接