It's annoying too - it's not DRY
It's true. But there is only so much that you can do for the end-to-end care that permeates every type that you have. You must use the logger everywhere, so you must have a property on these types.
So, let's see what we can do about it.
Singleton
The singletones are terrible <flame-suit-on> .
I recommend sticking to the injection properties, as you did with the second example. This is the best factoring you can do without resorting to magic. It is better to have an explicit dependency than to hide it with a singleton.
But if singles save you considerable time, including all the refactoring you will ever have to do (crystal ball time!), I suppose you could live with them. If ever there has been use of Singleton, perhaps it is. Keep in mind that the cost, if you ever want to change your mind, will be about as high as it is.
If you do, check out the answers of other people using the Registry template (see description), and those who register (reset) a singleton factory, rather than a single instance of the log.
There are other alternatives that may work just as well, without any compromise, so you should check them out first.
Visual Studio Code Snippets
You can use Visual Studio code snippets to speed up the entry of this repeating code. You can enter something like a logger tab , and the code will magically display for you.
Using AOP for DRY off
You can eliminate some of this property injection code by using an AOP-oriented programming (AOP) framework such as PostSharp to automatically generate some of it.
It might look something like this when you are done:
[InjectedLogger] public ILogger Logger { get; set; }
You can also use your sample method tracking code to automatically track the input and output of the method code, which may eliminate the need to add some of the logger properties together. You can apply the attribute at the class level or in the namespace:
[Trace] public class MyClass {