Reputation: 54821
I have the special case where an object needs to be a singleton on a per thread basis. So I'd like to use a static factory method of a Factory
class to instantiate those instances. To ensure that the factory class is used (since it caches per thread) the constructor needs to be protected.
So let's say I have a class like this.
public class XXXX : Model {
protected XXXX() {
}
}
I would like to use a factory class like this.
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];
}
}
Then later I can get a reference to each singleton like this, and the reference will be unique for each thread.
XXXX m = Factory.Instance<XXXX>();
How can I do this so that the Factory
class has access to create instances. One issue is that classes will be defined in other DLLs that will be loaded at run-time. All I can know is that they are derived from Model
and have protected/private
constructors.
Upvotes: 3
Views: 2040
Reputation: 11
If what you are looking to implement is: this Class and ANY of its derivatives MUST use the class factory method, no matter who implements the derived classes (lib consumer, in an other assembly, etc).
In the base class, declare a private no arg constructur and a constructor with a private "key" arg. then declare a templated method that takes a type as argument and uses reflection to instanciate the class.
Why the magic key? because you need at least one public or protected constructor to be able to specialize the base class and as soon as you do that, your letting child classes choose to enforce or not factory use.
A down side is the use of Invoke. slows things down a bit. In the eventually where this is an issue you can always invoke the compile at runtime to spew out the proper delegate for a given type and store those. so you slowly build a dictionary of constructor delegates for each type. but's beyond the scope of this question.
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;
}
}
Upvotes: 0
Reputation: 100620
Some options:
Approximate code for delegate approach:
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)] ());
}
}
Upvotes: 4
Reputation: 6717
Your XXXX
classes either need a public constructor, or they need an internal constructor and you define the assembly that contains your factory as a friend assembly inside the assemblies that contain the XXXX
classes.
See http://msdn.microsoft.com/en-us/library/0tke9fxk%28v=vs.80%29.aspx
Upvotes: 1