I am currently porting some code from C++ into C# and have come a little stuck with recreating my template factory class. I was wandering if anyone could give me any hints or pointers as to where I would start. First I'll post the C++ code, then I will post a description and use-case example.
Code:
FactoryTemplate.h
#include <map>
#include "../Utilities/Logger.h"
namespace XF
{
namespace Utilities
{
#define XF_FACTORY_JOIN_MACRO( X, Y) XF_FACTORY_DO_JOIN( X, Y )
#define XF_FACTORY_DO_JOIN( X, Y ) XF_FACTORY_DO_JOIN2(X,Y)
#define XF_FACTORY_DO_JOIN2( X, Y ) X##Y
#define XF_FACTORY_CLASS_NAME XF_FACTORY_JOIN_MACRO(Factory, XF_FACTORY_NUM_ARGS)
#define XF_FACTORY_MAKER_BASE_NAME XF_FACTORY_JOIN_MACRO(MakerBase, XF_FACTORY_NUM_ARGS)
#define XF_FACTORY_MAKER_NAME XF_FACTORY_JOIN_MACRO(Maker, XF_FACTORY_NUM_ARGS)
#if XF_FACTORY_NUM_ARGS > 0
#define XF_FACTORY_SEPERATOR ,
#else
#define XF_FACTORY_SEPERATOR
#endif
template <typename Type, typename Key XF_FACTORY_SEPERATOR XF_FACTORY_TEMPLATE_ARGS>
class XF_FACTORY_CLASS_NAME
{
private:
template <typename Type, typename Key XF_FACTORY_SEPERATOR XF_FACTORY_TEMPLATE_ARGS>
class XF_FACTORY_MAKER_BASE_NAME
{
public:
typedef typename Type BaseType;
typedef typename Key KeyType;
public:
XF_FACTORY_MAKER_BASE_NAME(const KeyType& k):key(k) {}
const KeyType &GetKey() {return key;}
virtual BaseType* Create(XF_FACTORY_ARG_PARAMS) = 0;
virtual std::string GetMakeTypeName() = 0;
private:
KeyType key;
};
template <typename BaseType, typename Make, typename Key XF_FACTORY_SEPERATOR XF_FACTORY_TEMPLATE_ARGS>
class XF_FACTORY_MAKER_NAME : public XF_FACTORY_MAKER_BASE_NAME<BaseType, Key XF_FACTORY_SEPERATOR XF_FACTORY_ARGS>
{
public:
typedef typename Make MakeType;
XF_FACTORY_MAKER_NAME(const KeyType &key) : XF_FACTORY_MAKER_BASE_NAME(key) {}
BaseType* Create(XF_FACTORY_ARG_PARAMS)
{
return new MakeType(XF_FACTORY_PARAMS);
}
std::string GetMakeTypeName(){return typeid(MakeType).name();}
};
typedef typename XF_FACTORY_MAKER_BASE_NAME<Type, Key XF_FACTORY_SEPERATOR XF_FACTORY_TEMPLATE_ARGS> MakerBaseType;
public:
typedef typename Type ObjectType;
typedef typename Key KeyType;
XF_FACTORY_CLASS_NAME(){}
~XF_FACTORY_CLASS_NAME()
{
UnregisterTypes();
}
template <typename CreationType>
void RegisterType(const KeyType &key)
{
MakerCollectionIt it(makers.find(key));
if(it == makers.end())
{
MakerBaseType *newMaker
= new XF_FACTORY_MAKER_NAME<ObjectType, CreationType, KeyType XF_FACTORY_SEPERATOR XF_FACTORY_TEMPLATE_ARGS>(key);
makers.insert(std::make_pair(key, newMaker));
LOG_INFO << "Type registered: ([" << typeid(CreationType).name() << "] - '" << key << "')";
}
else
{
LOG_WARNING << "Attempting to register type using duplicate key ('" << key << "')" << Logging::LnBreak
<< " Original: [" << it->second->GetMakeTypeName() << "]" << Logging::LnBreak
<< " New: [" << typeid(CreationType).name() << "]" << Logging::LnBreak
<< " Request Ignored!";
}
}
void UnregisterTypes()
{
for(MakerCollectionIt it(makers.begin()); it != makers.end(); ++it)
{
delete it->second;
}
makers.clear();
}
ObjectType* Create(const KeyType &key XF_FACTORY_SEPERATOR XF_FACTORY_ARG_PARAMS)
{
MakerCollectionIt it(makers.find(key));
return it == makers.end() ? NULL : it->second->Create(XF_FACTORY_PARAMS);
}
protected:
typedef std::map<KeyType, MakerBaseType*> MakerCollection;
typedef typename MakerCollection::iterator MakerCollectionIt;
MakerCollection makers;
};
}
}
#undef XF_FACTORY_JOIN_MACRO
#undef XF_FACTORY_DO_JOIN
#undef XF_FACTORY_DO_JOIN2
#undef XF_FACTORY_CLASS_NAME
#undef XF_FACTORY_SEPERATOR
#undef XF_FACTORY_MAKER_NAME
#undef XF_FACTORY_MAKER_BASE_NAME
Factory.h
#ifndef XF_UTILITIES_FACTORY_H
#define XF_UTILITIES_FACTORY_H
#define XF_FACTORY_NUM_ARGS 0
#define XF_FACTORY_TEMPLATE_ARGS
#define XF_FACTORY_ARGS
#define XF_FACTORY_ARG_PARAMS
#define XF_FACTORY_PARAMS
#include "FactoryTemplate.h"
#undef XF_FACTORY_NUM_ARGS
#undef XF_FACTORY_ARGS
#undef XF_FACTORY_TEMPLATE_ARGS
#undef XF_FACTORY_ARG_PARAMS
#undef XF_FACTORY_PARAMS
#define XF_FACTORY_NUM_ARGS 1
#define XF_FACTORY_TEMPLATE_ARGS typename A1
#define XF_FACTORY_ARGS A1
#define XF_FACTORY_ARG_PARAMS A1 a1
#define XF_FACTORY_PARAMS a1
#include "FactoryTemplate.h"
#undef XF_FACTORY_NUM_ARGS
#undef XF_FACTORY_ARGS
#undef XF_FACTORY_TEMPLATE_ARGS
#undef XF_FACTORY_ARG_PARAMS
#undef XF_FACTORY_PARAMS
#define XF_FACTORY_NUM_ARGS 2
#define XF_FACTORY_TEMPLATE_ARGS typename A1, typename A2
#define XF_FACTORY_ARGS A1, A2
#define XF_FACTORY_ARG_PARAMS A1 a1, A2 a2
#define XF_FACTORY_PARAMS a1, a2
#include "FactoryTemplate.h"
#undef XF_FACTORY_NUM_ARGS
#undef XF_FACTORY_ARGS
#undef XF_FACTORY_TEMPLATE_ARGS
#undef XF_FACTORY_ARG_PARAMS
#undef XF_FACTORY_PARAMS
#endif
The user #includes Factory.h to use the factory.
The above code will generate 3 templates Factory0<ReturnType>, Factory2<ReturnType, ParamType1> and Factory2<ReturnType, ParamType1, ParamType2> which can then be used to create factory's templated to any type the user requires.
Use case:
class A {};
class AA : public A {}
class AB : public A {}
class B {B(int, float){}};
class BA : public A{BA(int, float) : B(){}};
Factory0<A> f1;
Factory2<B, int, float> f2;
f1.RegisterType<AA>("AA");
f1.RegisterType<AB>("AB");
f2.RegisterType<BA>("BA");
A *a1 = f1.Create("AA");
A *a2 = f1.Create("AB");
B *b1 = f2.Create("BA", 1, 2.0f);
B *b2 = f2.Create("BA", 4, 7.8f);
With no direct replacement for the way I use #define in the above code to generate the class names, as well as fill in the argument types/ parameters etc I'm completely stumped on what mechanisms are available.
Any help or pointers would be greatly appreciated.
Thanks,
Scott