3

我有一个特殊情况,一个对象需要在每个线程的基础上成为一个单例。所以我想使用一个Factory类的静态工厂方法来实例化这些实例。为了确保使用工厂类(因为它按线程缓存),需要保护构造函数。

所以假设我有这样的课程。

public class XXXX : Model {
    protected XXXX() {
    }
}

我想使用这样的工厂类。

public class Factory {

     private static Dictionary<int,Model> _singletons;

     public static T Instance() where T : Model {
          int thread = Thread.CurrentThread.ManagedThreadId;
          if(!_singletons.ContainsKey(thread))
          {
              _singletons[thread] = new T();
          }
          return (T)_singletons[thread];
     }
}

然后稍后我可以像这样获得对每个单例的引用,并且每个线程的引用都是唯一的。

XXXX m = Factory.Instance<XXXX>();

我怎样才能做到这一点,以便Factory该类有权创建实例。一个问题是类将在其他将在运行时加载的 DLL 中定义。我所知道的是它们派生自Model并具有protected/private构造函数。

4

3 回答 3

4

一些选项:

  • 反射
  • 注册使用工厂类创建类的委托
  • 配置您的 DI 容器以按照您需要的那种类型的类的方式运行

委托方法的近似代码:

public class Factory {
   private static Dictionary<Type, Func<Model>> creators;
   public void AddCreator<T>(Func<T> creator) where T:Model
   {
      creators.Add(typeof(T), ()=> creator());
   }

   public static T Instance() where T : Model 
   {
       return (T)(creators[typeof(T)] ());
   }
}
于 2013-05-17T00:54:46.637 回答
1

您的XXXX类要么需要公共构造函数,要么需要内部构造函数,并且您将包含您的工厂的程序集定义为包含XXXX类的程序集中的友元程序集。

请参阅http://msdn.microsoft.com/en-us/library/0tke9fxk%28v=vs.80%29.aspx

于 2013-05-17T00:52:06.987 回答
0

如果您要实现的是:该类及其任何派生类必须使用类工厂方法,无论谁实现派生类(lib 使用者,在其他程序集中等)。

在基类中,声明一个私有的无参数构造函数和一个带有私有“键”参数的构造函数。然后声明一个模板化方法,该方法将类型作为参数并使用反射来实例化该类。

为什么是魔法钥匙?因为您至少需要一个公共或受保护的构造函数才能专门化基类,并且一旦这样做,您就可以让子类选择强制使用或不使用工厂使用。

不利的一面是使用调用。让事情变慢一点。最终,如果这是一个问题,您总是可以在运行时调用编译来为给定类型生成正确的委托并存储它们。所以你慢慢地为每种类型构建一个构造函数委托的字典。但超出了这个问题的范围。

public class BaseClass 
{
    private static string factoryKey = "sdfdsfdsfdsfhdfdsgdfsgd";
    private BaseClass()
    {
        throw new ArgumentException("error");
    }

    protected BaseClass( string key)
    {
        if( key != factoryKey)
            throw new ArgumentException("error");
    }

    public static T CreateInstance<T>() where T : BaseClass
    {
        Type type = typeof(T);
        var ctor = type.GetConstructor(new[] { typeof(string) });
        var instance = ctor.Invoke(new object[] { factoryKey }) as T;

        return instance;
    }

}
于 2017-03-03T21:16:09.680 回答