I am looking for a c# equivelent of my code for a pluggable factory. The advantage of the linked method is that static initialization result in a push operation, where each plugin adds itself to the factory.
C++ code for a pluggable factory: (http://codepad.org/7pgzaaAK)
// base class for plugins
class Foo{
public:
virtual std::string getName()const=0;
virtual void exercise()const=0;
};
// plugin factory
class FooFactory{
public:
static Foo* GetA(std::string s);
typedef std::map<std::string,Foo*(*)(void)> mapType;
static mapType& getA();
};
FooFactory::mapType& FooFactory::getA(){static mapType getA;return getA;}
Foo* FooFactory::GetA(std::string s)
{return getA().find(s)!=getA().end()?getA()[s]():0;} // to simplify access
// helper function to add the fun
template<typename T>
Foo* getNew(){ return new T; }
// use the CRTP to automatically register the object with the factory.
template <typename T> struct Reg { Reg() { /*cout << "registering a " << T().getName( <<endl;*/
FooFactory::getA().insert(std::pair<std::string, Foo*(*)()>(T().getName(), &getNew<T>));} };
template <typename T>
class Foo_reg:public Foo{
public:
Foo_reg(){®}; // using a reff to the static is enough to force initialization of the static earlier
static Reg<T> reg;
};
template <typename T> Reg<T> Foo_reg<T>::reg;
/////////////////
class FooBar:public Foo_reg<FooBar>{ // automatic registration with the factory
public:
FooBar(){a=10;}
virtual std::string getName()const{return "Foo Bar";}
virtual void exercise()const {cout <<a;}
private:
int a;
};
// exercise the factory and objects.
int main(){
Foo* foo=FooFactory::GetA("Foo Bar");
foo->exercise();
}
In C# i can see 2 ways of doing this, both of them pull operations
-
Have an explicit pre-built list of all plugins, which has to be maintained seperatly from the plugins themselves.
-
Use code reflection to iterate through all types, checking if they are castable to Foo and initialize their statics, on any dll load and program start.
Is it possible to do this without having to resort to these methods?
I wouldnt worry about reflection to much. Even PEX has no trouble using it. Simply put, by reflection, you’re just checking the metadata of an assembly and see if it defined any classes that implement a certain interface or are marked with a certain attribute, this is very fast! Anyways, the CLR will never run code that is not being called explicitly so no, you have to resort to some kind of pulling mechanism (even if you make it look like a push mechanism)