2

I order to be able to read files from another project, I'm copying the write code and adjusting it to my need.

I have come to a curios construct that seems really ugly, but I don't know if there is another way to deal with it.

The code looks something like this:

int type = reader.readInt32():
BaseClass p = BaseClass.Instantiate((BaseClassEnum)type);
object.Read(reader);

This code seems nice, and it is, but BaseClass.Instantiate(BaseClassEnum type) method leaves something to be desired.

Basically, it's a giant switch case statement that instantiates a subclass of the baseclass according to the type parameter passed.

Is there some way to avoid switch case here? Can I create a dictionary where I map BaseClassEnum to some kind of class reference that would allow me to call it's constructor? Something like:

Dictionary<int, ???> bindings = new Dictionary<int, ???>(){
    {BaseClassEnum1, SubClass1},
    {BaseClassEnum2, SubClass2}
}

//...

//Assuming SubClass1 has a constructor SubClass1()
BaseClass p = new bindings[BaseClassEnum1]();

//I could even create a new constructor SubClass(BinaryReader reader) and do
BaseCoass p = new bindings[BaseClassEnum1](reader);

In the end, the code would look something like this:

BaseClass p = new bindings[(BaseClassEnum)reader.ReadInt32()](reader);
Karlovsky120
  • 6,212
  • 8
  • 41
  • 94
  • 1
    Related https://stackoverflow.com/questions/31768610/reflection-in-factory-design-patterns-in-java-or-c-sharp – ChrisF Dec 22 '18 at 13:40

2 Answers2

3

A class/type factory (which is what you are creating), is implemented in one of four basic ways.

  1. Switch statement or equivalent or a series of if/then/else statements
  2. Dictionary or other structure that allows mapping a value to a particular type
  3. Some variation of call by name (which in C# means reflection)
  4. Event subscription (not used very often) which will probably use one of the other methods internally.

Switch statements are ugly and of course somewhat error prone, dictionaries are just about as ugly and have their own errors, but are easier to test. Reflection is generally slower and event subscription is slower yet.

So, there is no silver bullet.

What you are describing would look like:

var binding = new Dictionary<int, Func<BaseClass>>(){{BaseClassEnum1, ()=> new SubClass1()},
                                                   {BaseClassEnum2, ()=>new SubClass2()}};


var p = new bindings[BaseClassEnum1]();

Working example at https://dotnetfiddle.net/rWwCjw (with a few difference in variable names).

I should note that both the above and the example are a bit simplified, in particular if this is supposed to cover all of the possible SubClasses in your application, the dictionary should be its own property/function so that you can test (via reflection) that all of the subclasses in your application are present in the list.

jmoreno
  • 12,752
  • 4
  • 60
  • 91
1

If you change the question marks ??? to Type you can use var p = Activator.Createinstance(binding[BaseClassEnum1], reader)

Activator.Createinstance

Jens Granlund
  • 4,950
  • 1
  • 31
  • 31