0

I have a library with some classes that realize the same interface:

internal class MyObj1 : IMyObj {
     public MyObj1(string param1, int param2) {}
}

internal class MyObj2 : IMyObj {
     public MyObj2(bool param1, string param2, int param3) {}
}

internal class MyObj3 : IMyObj {
     public MyObj3(string param1, int param2) {}
}

I want to create an objects factory that allows to get access to MyObj1, MyObj2, MyObj3 only by IMyObj:

public class MyObjFactory {
    public IMyObj Create<T>() {
        return (IMyObj)Activator.CreateInstance(typeof(T));
    }
}

I don't know how to pass constructor arguments to the factory method. Any idea?

pepeevich
  • 183
  • 1
  • 4
  • 20
  • Why is `new MyObjectFactory.Create("a", 1)` preferable to `new MyObj1("a", 1)`? – mjwills Feb 13 '18 at 11:52
  • See [Factory method with DI and IoC](https://stackoverflow.com/a/31971691) – NightOwl888 Feb 13 '18 at 12:28
  • What @NightOwl888 just said - that's exactly what you need. Reflection and `Activator.CreateInstance()` solves nothing. It just moves the problem and paints you into a corner. You still have to figure out where to get constructor arguments from, or worse, it leads you to start creating only classes with only empty constructors. I'm working on an example. – Scott Hannen Feb 13 '18 at 14:02

3 Answers3

1

I would recommend not using Activator.CreateInstance since it is relatively slow, and there is a reduction in runtime safety (e.g. if you get the number of constructor parameters wrong it will throw an exception at runtime).

I would suggest something like:

public IMyObj CreateType1(string param1, int param2)
{
    return new MyObj1(param1, param2);
}    

public IMyObj CreateType2(bool param1, string param2, int param3) 
{
    return new MyObj2(param1, param2, param3);
}
mjwills
  • 23,389
  • 6
  • 40
  • 63
1

It sounds like this is where you're at:

a) You don't want classes to create the additional classes they depend on, because that couples them together. Each class would have to know too much about the classes it depends on, such as their constructor arguments.

b) You create a factory to separate the creation of those objects.

c) You discover that the problem you had in (a) has now moved to (b), but it's exactly the same problem, only with more classes. Now your factory has to create class instances. But where will it get the constructor arguments it needs to create those objects?

One solution is using a DI container. If that is entirely familiar then that's 10% bad news and 90% good news. There's a little bit of a learning curve, but it's not bad. The 90% good news part is that you've reached a point where you realize you need it, and it's going to become an extraordinarily valuable tool.

When I say "DI container" - also called an "IoC (Inversion of Control) container," that refers to tools like Autofac, Unity, or Castle Windsor. I work primarily with Windsor so I use that in examples.

A DI container is a tool that creates objects for you without explicitly calling the constructors. (This explanation is 100% certain to be insufficient - you'll need to Google more. Trust me, it's worth it.)

Suppose you have a class that depends on several abstractions (interfaces.) And the implementations of those interfaces depend on more abstractions:

public class ClassThatDependsOnThreeThings
{
    private readonly IThingOne _thingOne;
    private readonly IThingTwo _thingTwo;
    private readonly IThingThree _thingThree;

    public ClassThatDependsOnThreeThings(IThingOne thingOne, IThingTwo thingTwo, IThingThree thingThree)
    {
        _thingOne = thingOne;
        _thingTwo = thingTwo;
        _thingThree = thingThree;
    }
}

public class ThingOne : IThingOne
{
    private readonly IThingFour _thingFour;
    private readonly IThingFive _thingFive;

    public ThingOne(IThingFour thingFour, IThingFive thingFive)
    {
        _thingFour = thingFour;
        _thingFive = thingFive;
    }
}

public class ThingTwo : IThingTwo
{
    private readonly IThingThree _thingThree;
    private readonly IThingSix _thingSix;

    public ThingTwo(IThingThree thingThree, IThingSix thingSix)
    {
        _thingThree = thingThree;
        _thingSix = thingSix;
    }
}

public class ThingThree : IThingThree
{
    private readonly string _connectionString;

    public ThingThree(string connectionString)
    {
        _connectionString = connectionString;
    }
}

This is good because each individual class is simple and easy to test. But how in the world are you going to create a factory to create all of these objects for you? That factory would have to know/contain everything needed to create every single one of the objects.

The individual classes are better off, but composing them or creating instances becomes a major headache. What if there are parts of your code that only need one of these - do you create another factory? What if you have to change one of these classes so that now it has more or different dependencies? Now you have to go back and fix all your factories. That's a nightmare.

A DI container (again, this example is using Castle.Windsor) allows you to do this. At first it's going to look like more work, or just moving the problem around. But it's not:

var container = new WindsorContainer();
container.Register(
    Component.For<ClassThatDependsOnThreeThings>(),
    Component.For<IThingOne, ThingOne>(),
    Component.For<IThingTwo, ThingTwo>(),
    Component.For<IThingThree, ThingThree>()
        .DependsOn(Dependency.OnValue("connectionString", ConfigurationManager.ConnectionStrings["xyz"].ConnectionString)),
    Component.For<IThingFour,IThingFour>(),
    Component.For<IThingFive, IThingFive>(),
    Component.For<IThingSix, IThingSix>()
);

Now, if you do this:

var thing = container.Resolve<ClassThatDependsOnThreeThings>();

or

var thingTwo = container.Resolve<IThingTwo>();

as long as you've registered the type with the container and you've also registered whatever types are needed to fulfill all the nested dependencies, the container creates each object as needed, calling the constructor of each object, until it can finally create the object you asked for.

Another detail you'll probably notice is that none of these classes create the things they depend on. There is no new ThingThree(). Whatever each class depends on is specified in its constructor. That's one of the fundamental concepts of dependency injection. If a class just receives and instance of IThingThree then it really never knows what the implementation is. It only depends on the interface and doesn't know anything about the implementation. That works toward Dependency Inversion, the "D" in SOLID. It helps protect your classes from getting coupled to specific implementation details.

That's very powerful. It means that, when properly configured, at any point in your code you can just ask for the dependency you need - usually as an interface - and just receive it. The class that needs it doesn't have to know how to create it. That means that 90% of the time you don't even need a factory at all. The constructor of your class just says what it needs, and container provides it.

(If you actually do need a factory, which does happen in some cases, Windsor and some other containers help you to create one. Here's an example.)

Part of getting this to work involves learning how to configure the type of application you're using to use a DI container. For example, in an ASP.NET MVC application you would configure the container to create your controllers for you. That way if your controllers depend on more things, the container can create those things as needed. ASP.NET Core makes it easier by providing its own DI container so that all you have to do is register your various components.

This is an incomplete answer because it describes what the solution is without telling you how to implement it. That will require some more searching on your part, such as "How do I configure XYZ for dependency injection," or just learning more about the concept in general. One author called it something like a $5 term for a $.50 concept. It looks complicated and confusing until you try it and see how it works. Then you'll see why it's built into ASP.NET Core, Angular, and why all sorts of languages use dependency injection.

When you reach the point - as you have - where you have the problems that DI solves, that's really exciting because it means you realize that there must be a better, cleaner way to accomplish what you're trying to do. The good news is that there is. Learning it and using it will have a ripple effect throughout your code, enabling you to better apply SOLID principles and write smaller classes that are easier to unit test.

Scott Hannen
  • 27,588
  • 3
  • 45
  • 62
  • Thank you for detailed answer. I read it and got that I should read more about DI. However, I ain't sure that DI container is a good idea for my goal. Looks like a lot of code to do small thing. What do you think about this? My goal is simple: 1) I want to get all of my objects only by common interface (IMyObj), 2) I want to deny create a class instance directly. That is all what I need. – pepeevich Feb 14 '18 at 03:07
0

Use Activator.CreateInstance Method (Type, Object[])

Creates an instance of the specified type using the constructor that best matches the specified parameters.

public IMyObj Create<T>(params object[] args) 
{
    return (IMyObj)Activator.CreateInstance(typeof(T),args);
}

Alternatively

public IMyObj Create<T>(string param1, int param2) where T : MyObj1 
{
    return (IMyObj)Activator.CreateInstance(typeof(T),args);
}

public IMyObj Create<T>(bool param1, string param2, int param3) where T : MyObj2 
{
    return (IMyObj)Activator.CreateInstance(typeof(T),args);
}
...
...
TheGeneral
  • 79,002
  • 9
  • 103
  • 141
  • Looks like what I need. Could you please advice me how can I improve this code snippet to make args clear for person who use MyObjFactory? Now person doesn't know what he should pass as "args". – pepeevich Feb 13 '18 at 11:48
  • Looks nice. Alternative approach is clear and solves my issue. Do you recommend to use it instead of the first? – pepeevich Feb 13 '18 at 11:54
  • 2
    The factory pattern isn't really adding much value to this, as mjwills stated. Why is new `MyObjectFactory.Create("a", 1)` preferable to new `MyObj1("a", 1)`? I.e its actually less characters to do the later and spin up your objects as they are – TheGeneral Feb 13 '18 at 11:56
  • @mjwills, because a factory solves the main issue - I can get access only to IMyObj and can't get MyObj1, MyObj2 or MyObj3 directly. – pepeevich Feb 13 '18 at 12:02
  • @mjwills Looks simpler. do you know how can I prevent a creation of MyObj1 directly, and allow it only in CreateType1 method? internal modifier for constructor doesn't solve this issue. – pepeevich Feb 13 '18 at 12:12
  • @mjwills ahah, okay :P Thank you. Could you post your answer? – pepeevich Feb 13 '18 at 12:16
  • The problem with this approach is that it's no different from calling `new Thing(arg1, arg2, arg3.)` Now you're just calling `Activator.CreateInstance(typeof(Thing), arg1, arg2, arg3)`. It doesn't change anything. The factory still has to know all the arguments. Or it pushes you to create classes with default constructors just so that `Activator.CreateInstance` will work, and the classes start depending on static objects and properties - they become untestable. – Scott Hannen Feb 13 '18 at 16:17
  • @ScottHannen agreed DI/IOC is a beautiful thing, however with simple parameters and the simple requirements i'm not sure it adds much... Though on saying that its always good design – TheGeneral Feb 13 '18 at 23:29
  • 1
    When the student is ready the master appears. (I'm not the master - it just makes for a good illustration.) When someone finds themselves creating factories and wondering - wait - where will the factory get the values that it inserts into the objects it creates, then it is time for the DI container to appear. The developer has likely already been held back by the constraints of *not* knowing about it. The time has come to embrace the awesomeness. – Scott Hannen Feb 13 '18 at 23:39