2

I know that this argument is well covered here on S.O., especially in

Why not use an IoC container to resolve dependencies for entities/business objects?

but also in other questions; but doubts remain.

I've used the wording type that collects data and not entity or business object to keep the question focused on principles.

So, if I've a type like this that depends on primitive data like this (or even with more fields):

public class Animal {
  private readonly string name;
  private readonly string nickname;
  private readonly int weight;
  private readonly int heightAtWithers:
  private readonly Color mainColor;
  private raadonly bool isMale;
  private readonly bool isAggressive;

  public Animal(string name, string nickname, int weight,
                int heightAtWithers, Color mainColor,
                bool is Male, bool isAggressive)
  {
    // remainder omitted
  }

  public string Name { get { return this.name; } }

  // remainder omitted
}

is this a case of constructor over-injection?

In Mark Seemann book is suggested to keep low the number of dependencies, 2 to 4 (if I am not wrong).

Is possible that for type of this kind that this anti-pattern does not apply?

Community
  • 1
  • 1
jay
  • 1,510
  • 2
  • 11
  • 19

2 Answers2

8

Those aren't really dependencies in the normal sense - they're the data of the entity. It's not like those things are providing polymorphic services, etc. I wouldn't usually expect a dependency injection framework (or IoC container) to create objects like this - usually it would be part of an ORM or hand-written code.

It does become a bit of a pain to call such constructors, and if you want to provide default values that becomes tricky too. Optional parameters and named arguments can help if you're using C# 4 or higher though. (They do require that the defaults are known at compile-time, mind you.)

One alternative is to create a mutable builder type, with relevant defaults. I usually make it a nested class. You could either give it a parameterless constructor and just validate that everything required is present when you build the builder, or provide a constructor with all the required values, and just leave the properties for optional values. Then you can use object initializers to create instances pleasantly:

var animal = new Animal.Builder("Frederick") {
                 NickName = "Freddie",
                 Weight = 10,
                 MainColor = Color.Brown
             }).Build();

Writing the builder is irritating boiler-plate work, but it can be useful. If you find that you do always have the relevant information to hand when you're constructing the instance, it may be simpler just to stick with your current constructor. Consider using named arguments to make the meaning of each argument clearer, particularly when there are multiple parameters with the same type:

var animal = new Animal(name: "Frederick", nickname: "Freddie",
                        weight: 10, heightAtWithers: 20,
                        Color.Brown, isMale:true, isAggressive: false);
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 1
    +1, for the the builder. It completes my knowledge on the argument, started with this [question](http://stackoverflow.com/questions/15088773/design-a-mutable-class-that-after-its-consumed-becomes-immutable). – jay Mar 21 '13 at 07:07
  • 1
    +1 A builder is definitely the way to go. No hard rule, but IMO any constructor that needs more than 4 arguments actually needs a builder. Or a simple read-write interface separation. And builders are an excellent excuse to finally get familiar with that fancy templating system your favorite IDE provides but you never use ;) – Creynders Mar 21 '13 at 18:10
5

IIRC, when Mark talks about Constructor Over-Injection it is in the light of a SRP violation.

A class that depends on lots and lots of other services most likely does more than one thing.
The same is not necessarily true for a class that depends on a lot of primitives.

Having said this, a dependency of a primitive data type and the data of a "data holder class" are two different things.

Compare your class with the class described in the article you linked:
DbChartReader needs top to be able to do its work - it is a dependency.
Animal doesn't do any work. The data passed in via the constructor basically is the object - the constructor parameters are just that: data.

Daniel Hilgarth
  • 171,043
  • 40
  • 335
  • 443
  • +1 @Daniel Hilgarth. I was seeking in Mark book for definition like that. *Data holder class* definition _replies_ to my question. It's a different type that must be treated in a different way. – jay Mar 21 '13 at 07:12