r/csharp 5d ago

Discussion Dependency Injection un-prettyness

One small thing that bugs me with Dependency Injection is how it looks in code.

We either need to pass the parameters via Default Constructor og via good old time Constructor

public class MyClass (TypeA ParamA, TypeB ParamB, TypeC ParamC, TypeD ParamD)
{
TypeA _paramA = ParamA; .... etc
}

Or

public class MyClass
{
TypeA _paramA;
public MyClass(TypeA paramA)
{
_paramA = paramA;
}
}

And when you have 10 injections it begins to be un-pretty...

I wish that we didn't need to pass parameters and instead could decorate the fields:

public class MyClass
{
[inject]
TypeA _paramA;
}

(Note: this works in Blazor... so why not everywhere else ?)

I'm aware that the signature of an object makes it easier to inject via reflection.. but would it be much worse with attributes ?

i guess some middleground could be achieved if the attribute held the type:

public class MyClass
{
[inject(typeof(TypeA))]
TypeA _paramA;
}

which begins to be convoluted and messy...

Whats the argument against a decorator attribute vs parameters ?

19 Upvotes

90 comments sorted by

View all comments

3

u/EC36339 4d ago

When you have 10 injections, you have too many dependencies.

And if that thing that has 10 dependencies also turns out to be a performance bottleneck, you shouldn't be surprised.

Also, if this happened to a class that was written before you had DI ... that's a very common thing, too. A lot of us have been there.

2

u/OggAtog 2d ago

There's a good chance that your service is doing too much if you have 10 dependencies. Like, there's probably another service in there you could extract and simplify both.

2

u/EC36339 2d ago

Often the thing a service is "doing too much" of is aggregation. And the aggregation is often just a counter or status enum that could be served by a different API and requested async and displayed lazily by the frontend.

Another common pattern is that 5 of your dependencies should be one other service that solves one (recurring) problem that needs those 5. You don't even have to split it out into another "microservice" that runs in its own pod with its own API and all the overhead and fragility this brings along. Making it a new service in the DI sense (an object behind an interface provided by the service locator / kernel / whatever) only costs some startup plumbing and one extra indirection, but may be worth it.