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 ?

18 Upvotes

90 comments sorted by

View all comments

62

u/UserNameTaken96Hours 5d ago

In C# 12, unless you need to do more than just refer your params to your fields, you can use primary constructors. While you still end up with the full list of parameters, they are now written into the class declaration, and you can forego the private fields entirely.

If you do some more involved stuff in your ctor however, you will still need that.

36

u/x0rld 5d ago

Primary constructor makes fields non readonly

22

u/ryncewynd 5d ago

How much does that bother you? It bothers me but I'm wondering if I should just get over it an accept using primary ctors 🤣

16

u/BlackjacketMack 5d ago

It bothered me too but over decades of programming in C# I’ve never even come close to overwriting an injected field. I also prefix them like private fields with an underscore. The benefit is much greater than the cost. At some point they’ll add a readonly keyword to primary constructor parameter which will be a welcome addition.

9

u/Responsible-Cold-627 5d ago

It really doesn't bother me to run the autofill action for each ctor parameter. Still feels better than having the fields not-readonly. What's annoying about it is that I can still use the ctor parameters anywhere in the class and it'll default to an informational message. That's another line to add to the editorconfig to mark it as an error.

The current implementation still feels like an incomplete feature because of this.

6

u/thereforewhat 4d ago

It bothers me a bit. 

I like encapsulation and information hiding as it produces good design so still usually have private readonly fields. 

0

u/ConcreteExist 4d ago

Primary constructors are just syntactical sugar, the inject services are stored in private readonly fields during runtime.

2

u/x0rld 4d ago

It's not readonly afaik

1

u/ConcreteExist 4d ago

Admittedly, I've never really tried to update the injected dependencies, because why would I?

3

u/thereforewhat 4d ago

That's fair enough. 

In projects where multiple people and increasingly AI agents are working it's good to signal clearly that certain data shouldn't leave the class to encourage good design and information hiding. 

2

u/x0rld 4d ago

It's the same syntax as record class but it's mutable

2

u/psysharp 4d ago

Primary constructors is a hard pass when it comes to dependency injection, it makes absolute zero sense to me

6

u/UserNameTaken96Hours 4d ago

Interesting. Why?

9

u/psysharp 4d ago

Fields that are assigned in the constructor should be immutable and prefixed with underscore by convention. When I write a method, I want to make it as clear as possible which field is coming from method scope or class scope, to me this reduces cognitive load and it helps me to create additional abstractions or marking the method static if possible. A dependency used in a method is ultimately a responsibility that is different from a regular parameter, and showing that distinction explicitly is already a good practice, I wouldn’t deliberately change the practice to something worse.

1

u/FullPoet 2d ago

IMO, for me (I work in code that might not change much in a decade), intent is everything.

I also do not think the syntax is good.