10

I know this question has been asked before, but I have yet to see a short, clear answer, so I'm hoping they won't remove this question and I will now get a clear answer:

I am currently working in C# 5.0; .NET 4.5; VS 2012. I am mostly a Delphi guy although I've done lots with C#.

In Delphi I have written hundreds of class factories that use the following sort of design (MUCH SIMPLIFIED HERE):

unit uFactory;

interface


type

    TClassofMyClass = class of TMyClass;
    TFactoryDict = TDictionary<TMyEnum, TClassofMyClass>;

var fDict:TFactoryDict;

implementation  

procedure initDict;
begin

    fDict:=TFactoryDict.create;
    fDict.add(myEnum1, TMyClass1);
    fDict.add(myEnum2, TMyClass2);
    fDict.add(myEnum3, TMyClass3);

end;


function Factory(const aEnum: TMyEnum): TMyClass;

var

    ClassofMyClass: TClassofMyClass;

begin

    if fDict.TryGetValue(aEnum, ClassofMyClass) then

    result := ClassofMyClass.Create(aParam);

end;

end.

Now: HOW do I do something like this in C#?! Seems there is NO 'class of ' type in C#. Am I missing something? How can I implement this type of class factory simply and elegantly in C#? This design can be implemented in Python as well - why should C# be worse?!

3
  • Are TMyClass1 and TMyClass2 subclasses of TMyClass? Commented Apr 8, 2013 at 7:10
  • @martheen yes, that's enforced by class of TMyClass Commented Apr 8, 2013 at 7:23
  • Is this still missing from C#? Commented Dec 6, 2018 at 16:09

4 Answers 4

9

You can use Type:

Dictionary<ClassEnum, Type> TypeDictionary = new Dictionary<ClassEnum, Type>();

public void InitDictionary()
{
    TypeDictionary.Add(ClassEnum.FirstClass, typeof(FirstClass));
    //etc...
}

public object Factory(ClassEnum type)
{
    if (!TypeDictionary.ContainsKey(type))
        return null;

    var constructor = TypeDictionary[type].GetConstructor(....);
    return constructor.Invoke(....);
}

But I think you should use a generic method:

public T Factory<T>(): where T is MyBaseClass
{
    var type = typeof(T);
    var constructor = type.GetConstructor(....);
    return constructor.Invoke(....) as T;
}

Here is a variety for parameterized construction:

public T Factory<T>(params object[] args): where T is MyBaseClass
{
    var argList = new List<object>(args);
    var type = typeof(T);
    var argtypes = argList.Select(o => o.GetType()).ToArray();
    var constructor = type.GetConstructor(argtypes);
    return constructor.Invoke(args) as T;
}

And of course; As with the first example, this will throw a nullpointerexception if it can't find a matching constructor...

Sign up to request clarification or add additional context in comments.

7 Comments

Thanks - will check this out too. Another answer here also uses Invoke() and I've seen code on the web also using it in factory methods.
Note that this is a little less powerful than in Delphi, as you cannot enforce/rely on a subclass having a particular constructor. (And there is no generic constraint for constructors beside parameterless ones in C#.)
@O.R.Mapper: Delphi generics constructor constraint is also for parameterless ones. It is only when using meta classes that you can use more specific constructors as defined in the class hierarchy from TObject to the class that the meta class is defined on.
@MarjanVenema: Exactly, I was referring to C# being slightly inferior to Delphi's metaclasses.
@Stig-Rune Skansgård - I would also not need the Dictionary with enum based keys in Delphi, but the code runs on a webServer that takes XML based requests that are sent to the factory, so enums and a dictionary make it easier - can easily represent the enums in XML and send the XML enum straight to the factory. And of course sometimes I use parameterized constructors.
|
4
    class Potato
    {
    }

    class Potato1 : Potato
    {
        public Potato1(object[] param) { }
    }

    class Potato2 : Potato
    {
        public Potato2(object[] param);
    }

    enum MyEnum
    {
        E1, E2
    }

    Dictionary<MyEnum, Func<object[], Potato>> dict = new Dictionary<MyEnum, Func<object[], Potato>>(){
            {MyEnum.E1,(d)=>new Potato1(d)},
            {MyEnum.E2,(d)=>new Potato2(d)}
        };

    Potato Factory(MyEnum e, object[] param)
    {
        return dict[e](param);
    }

16 Comments

@Mikey: That's a lambda expression.
Isn't it a shame that there's no array MyEnum of ... in C#
Is the Invoke needed, or can you write dict[e]()
@Martheen That exists in Oxygene. Meta classes too I believe. I don't think .net imposes many limitations.
@Mikey Edited my answer. object[] could be changed to more specific example should you need it
|
1

If i understood you correct you want to have a reference to a static class. This is not possible in c#.

just one example of factory method implementation: http://www.codeproject.com/Tips/328826/implementing-Factory-Method-in-Csharp

1 Comment

'Class of' in Delphi is a metaClass - a type that can represent generically all the descendents of that base class and works with polymorphism depending on the descendant class represented. Nothing to do with static classes.
1

The C# language does not support meta classes.

So you'll have to implement your factory in another way. One way is to use a switch statement on an enum:

switch (aEnum)
{
     case myEnum1:
         return new MyClass1();
     case myEnum2:
         return new MyClass2();
     .....
}

Another commonly used option is to do it with reflection which would allow you to write code closer to what you are used to doing.

And yet another option is to replace your dictionary of classes with a dictionary of delegates that return a new instance of your object. With lambda syntax that option yields very clean code.

The disadvantage of reflection is that you give up compile time type safety. So whilst the reflection based approach is probably closest to the Delphi code in the question, it's not the route that I personally would choose.

Rather than trying to shoe horn your Delphi solution into a language that does not want that approach, I suggest you look for the most idiomatic C# solution. Start with a web search for class factory.

11 Comments

+1 - thank you. Yes, I know about switch {case:} - Delphi also has that for enums, as you well know. 'Start with a web search for class factory' - Thank you again. Now with all due respect, please read my question again. :-)
I think I understood the question. I meant that you'll find a variety of examples of C# factories on the web. Take a look at them and pick the approach that you like the best.
You got the clear answer. A simple statement that there is no equivalent to class of. I've outlined three possible ways to implement a factory. I think some web search will yield more ideas. You've probably done that already and just want to know if you can do it with meta classes. Well, not quite. The closest to meta classes is to use reflection.
But what? I'm just saying that there's loads of ways to do factories. It's hard to recommend one. You need to make your personal choice. And using a web search will give you some extra ideas beyond what is here. What's the harm? Although I personally can't think of any ideas beyond those I outlined, but I bet there are a few!
That's where I disagree. The closest to your code is the reflection based approach. But I would opt for a dictionary of delegates. I think you need to program to the language rather than try to take one languages solution to a language where it is ill suited. I personally don't like the reflection approach. I'd avoid reflection unless there was no clean alternative. That's the point of my final paragraph.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.