473,387 Members | 3,810 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,387 software developers and data experts.

C# - A Better Solution to a Generic Factory, or, is the callstack safe?

5
I found this thread: http://www.thescripts.com/forum/thread233505.html only marginally helpful.

It seems that going through the callstack is the only way to determine which function may have called the function currently being executed. Is this thread-safe, or are there other alternatives (I'm pretty new to reflection; can it do that)?

Here's a bit of the design that leads me to ask this question. I'd be interested to know if there is a better way to accomplish this.

The idea behind what I'm doing is to build a factory class, which will produce the derived forms of a certain base class. It looks something like this:

Expand|Select|Wrap|Line Numbers
  1.     static public class MyFactory<MyClassT> where MyClassT : MyClass, new()      
  2.     {
  3.  
  4.         static public MyClassT CreateMyClassT()
  5.         {
  6.             MyClassT retClass = new MyClassT();
  7.             // ... details here
  8.             return retClass;
  9.         }
  10.     }
  11.  
Now, I would like the derived (and base) classes to have constructors that can only be called by the factory. I had accomplished this the following way (which looks like it works like C++ friend classes):

Expand|Select|Wrap|Line Numbers
  1. [assembly: InternalsVisibleTo("MyFactory.cs")]
  2.  
  3.     public class MyClass_Derived : MyClass
  4.     {       
  5.         internal MyClass_Derived()
  6.             : base(MyClassEnum.DerivedType)
  7.         {
  8.         }
  9.     }
  10. }
  11.  
This worked until I tried templatizing the Factory (which almost became a hideous switch statement before I got smart. Or, at least, before I thought I got smart.

That leaves me with the following:
  • In order for the factory to create a new MyClassT, I need the : new() restriction.
  • With the : new() restriction, the class must have a public constructor with no arguments.
  • I wanted to get rid of the public argument-free constructor so that only the factory can construct these objects.

It appears that there is no way to have a generic Factory for a hierarchy of classes that doesn't have a public constructor. So, I thought, if I could check the class that called the constructor and throw an Exception if something other than the Factory tries to call it, I might approximate what I want.

Is there a better way to do this?

Thank you!

--

okay, so somehow I missed the .NET forum and ended up in C/C++. Sorry about that! (How do I move/delete this thread?)
Sep 7 '07 #1
5 2142
weaknessforcats
9,208 Expert Mod 8TB
Are you wanting a Parameterized Factory or an Abstract Factory??

Here is an example using a Parameterized Factory:

Factory.h:
Expand|Select|Wrap|Line Numbers
  1. class Base
  2. {
  3.  
  4. };
  5. class Factory
  6. {
  7.     public:
  8.         enum ObjectType {DERIVED, DERIVED1};
  9.         Base* BuildObject(enum ObjectType);
  10. };
  11.  
Factory.cpp:
Expand|Select|Wrap|Line Numbers
  1. class Derived : public Base
  2. {
  3.  
  4. };
  5. class Derived1 : public Base
  6. {
  7.  
  8. };
  9. Base* Factory::BuildObject(ObjectType arg)
  10. {
  11.     if (arg == Factory::DERIVED)
  12.     {
  13.         return new Derived;
  14.     }
  15.     //etc...
  16.     return 0;  //didn't work
  17. }
  18.  
And finally the code used by main():
Expand|Select|Wrap|Line Numbers
  1. #include "Factory.h"
  2.  
  3. int main()
  4. {
  5.     Factory f;
  6.     Base* obj = f.BuildObject(Factory::DERIVED);
  7. }
  8.  
The Factory.h does not include the class defintions for the derived classes. Since they are polymorphic, the base class public fuinctions consrtitute the interface so you don't need to know the derived class declarations.

There are other ways to do this using an Abstract Factory or by using a Singleton.\

In any case, do not use static classes or classes with static methods unless you have a gun to your head.
Sep 7 '07 #2
JosAH
11,448 Expert 8TB
@OP: I'll move your topic to the .NET forum.

kind regards,

Jos
Sep 7 '07 #3
Agrona
5
Are you wanting a Parameterized Factory or an Abstract Factory??
...
Expand|Select|Wrap|Line Numbers
  1. Base* Factory::BuildObject(ObjectType arg)
  2. {
  3.     if (arg == Factory::DERIVED)
  4.     {
  5.         return new Derived;
  6.     }
  7.     //etc...
  8.     return 0;  //didn't work
  9. }
  10.  
Thanks for responding. I do want a Parameterized Factory. However, I already had the solution you presented and was trying to go for something much more maintainable. Instead of the giant switch statement that would become the inside of this factory (is this enum a, then make type a; is it enum b, then make type b, etc.), I was trying to use Generics (templates) to make it simpler.

In know exactly what I'd want in C++, which would be something like the following (consider this pseudocode, as I'm not sitting in front of a C++ compiler. My apologies if its broken somewhere):

Expand|Select|Wrap|Line Numbers
  1. <typename T>
  2. class MyClassFactory<T>
  3. {
  4.  
  5.   // insert singleton implementation here
  6.  
  7.   <typename T>
  8.   T* MyClassFactory<T>::CreateMyClass()
  9.   {
  10.     return new T();
  11.   }
  12. }
  13.  
  14.  // The types I would create with the factory
  15.  
  16. class MyClassDerived public MyClass
  17. {
  18.   // Not sure on the syntax of friends and generic classes.
  19.   friend class MyClassFactory<MyClassDerived>;
  20.   private MyClassDerived() {} ;
  21.  
  22.   // more implementation
  23. }
  24.  
My post was that I seemed to be unable to produce something like this in C#.

Again, the ultimate goal here is to have a class that can only be produced by this factory. I have that at the moment, but only by using the less-than-desirable enum/switch solution. I want to move away from this, because the enums and derived classes are consistently being created and removed as the project grows and changes. Not having to cast the returned type to its derived class is also a pretty big bonus as far as ease of coding goes.

Thanks!

(Also, why the dislike of static?)
Sep 8 '07 #4
Agrona
5
@OP: I'll move your topic to the .NET forum.

kind regards,

Jos
Thanks for putting this in the right forum.
Sep 8 '07 #5
Agrona
5
OP Here.

I've been playing around, and this is exactly what I want. It's a shame that it's written in the wrong language. If anyone could help me convert this from C++ to C#, that would be awesome.


Expand|Select|Wrap|Line Numbers
  1. #include "GenericFactory.h"
  2. #include "ClassDefinitions.h"
  3.  
  4. int main(int argc, char * argv[])
  5. {
  6.     MyClassDerivedA * derivedA;
  7.     MyClassDerivedB * derivedB;
  8.  
  9.     derivedA = GenericFactory<MyClassDerivedA>::GetInstance()->CreateClass();
  10.     derivedB = GenericFactory<MyClassDerivedB>::GetInstance()->CreateClass();
  11.  
  12. //    derivedA = (MyClassDerivedA *)EnumControlledFactory::GetInstance()->CreateClass(true);
  13. //    derivedB = (MyClassDerivedB *)EnumControlledFactory::GetInstance()->CreateClass(false);
  14. }
  15.  
Expand|Select|Wrap|Line Numbers
  1. #ifndef GENERICFACTORY_H
  2. #define GENERICFACTORY_H
  3.  
  4. template <typename T> class GenericFactory
  5. {
  6. public:
  7.     static GenericFactory * GetInstance();
  8.     T * CreateClass();
  9.  
  10. private:
  11.     GenericFactory();
  12.     static GenericFactory * p_self;
  13. };
  14.  
  15. // implementation follows because C++ sucks with templates and includes.
  16.  
  17. template <typename T>
  18. GenericFactory<T> * GenericFactory<T>::p_self = 0;
  19.  
  20. template <typename T>
  21. GenericFactory<T>::GenericFactory() {};
  22.  
  23. template <typename T>
  24. GenericFactory<T> * GenericFactory<T>::GetInstance()
  25. {
  26.     if ( p_self = 0)    { p_self = new GenericFactory<T>(); }
  27.     return p_self;
  28. }
  29.  
  30. template <typename T>
  31. T * GenericFactory<T>::CreateClass()
  32. {
  33.     return new T();
  34. }
  35.  
  36. #endif
  37.  
Expand|Select|Wrap|Line Numbers
  1. #ifndef CLASS_DEFINITIONS_H
  2. #define CLASS_DEFINITIONS_H
  3.  
  4. // In actuality, these definitions appear in a library somewhere.
  5. class MyClass
  6. {
  7. protected:
  8.     MyClass() {};
  9. };
  10.  
  11. class MyClassDerivedA : MyClass
  12. {
  13.     friend class GenericFactory<MyClassDerivedA>;
  14. private:
  15.     MyClassDerivedA() {};
  16. };
  17.  
  18. class MyClassDerivedB  : MyClass
  19. {
  20.     friend class GenericFactory<MyClassDerivedB>;
  21. private:
  22.     MyClassDerivedB() {};
  23. };
  24.  
  25. #endif
  26.  
Sep 8 '07 #6

Sign in to post your reply or Sign up for a free account.

Similar topics

17
by: Medi Montaseri | last post by:
Hi, Given a collection of similar but not exact entities (or products) Toyota, Ford, Buick, etc; I am contemplating using the Abstraction pattern to provide a common interface to these products....
9
by: Patchwork | last post by:
Hi Everyone, I have a design related question (in C++) that I am hoping someone can help me with. It is related to my previous post but since it was pointed out that I was more or less asking...
3
by: SimonH | last post by:
Hi all, I would like to make a generic set of methods that could be called regardless of the database behind the scenes. One of the methods I would like would take a string sql statement and...
3
by: SimonH | last post by:
Hi all, I would like to make a generic set of methods that could be called regardless of the database behind the scenes. One of the methods I would like would take a string sql statement and...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.