2

So, to give some context, as that always helps, we are using LightInject and Log4Net and Common.Logging. If we initialize the logger as:

public static ILog Logger = LogManager.GetLogger<someType>();

the logger works the first time the class is instantiated (via LightInject) and never seems to log after that (or it may not even log the first time, hard to say sometimes).

If we change that line to this (notice the subtle difference) it works always.

public static readonly ILog Logger = LogManager.GetLogger<someType>();

So ... I get that a static readonly can only be set once for the class initialization, and be set either as we are doing or in a static constructor. But why does it "lose" the logger if we don't make it readonly?

jcolebrand
  • 15,923
  • 10
  • 71
  • 117
  • 2
    My guess would be that it is being overridden somehow, maybe by LightInject. It is impossible to say with what is here. You can try making it into a property and setting a break point on the setter. –  May 05 '16 at 21:32
  • You can also try making it protected or private, I know in Castle.Windsor's case it can only inject into public members. –  May 05 '16 at 21:34
  • Check this [answer](http://stackoverflow.com/a/968140/2050745) – Nejc Galof May 05 '16 at 21:39
  • 1
    What makes you think the logger gets lost? – xxbbcc May 05 '16 at 21:42
  • @hvd so sorry for my pedantic misstep. – jcolebrand May 05 '16 at 22:36
  • @xxbbcc because I see that the logs do not get handled by Log4net – jcolebrand May 05 '16 at 22:37
  • @Phaeze what can I provide to give more context? It's pretty barebones, and the only thing I change that fixes it is adding that keyword. I'm more curious about what the actual mechanics of the type system are that this happens. – jcolebrand May 05 '16 at 22:37
  • It *might* be that, when you add the readonly, LightInject inspects your variable modifier and skips from setting it (because it would give a runtime error). Are you executing the code with the option to stop on all exceptions? If not, do so. LightInject might be even catching some runtime exception – Luis Filipe May 05 '16 at 22:43
  • @LuisFilipe that is very possibly true, except LightInject isn't creating these properties, that's coming from the LogManager bit (note that there isn't a public setter here, it's being initialized. What is going on happened on a previous IOC framework as well. It's almost certainly truly a bug in common logging or Log4Net. – jcolebrand May 05 '16 at 22:46
  • @LuisFilipe isn't that what I said in my last paragraph of my question? – jcolebrand May 05 '16 at 22:47
  • @hvd the rollback I made was not childish, it was important to the distinction that I was looking to understand what happens. You're being rude with your assertions. The sarcasm about your pedantic comment is what comments are for, to let you know that while it's _possible_ that I should be calling them fields instead of properties, at the end of the day we ALL know that I mean the actual thing I defined, which was clear. I happen to know who made the change to my question and that is why I felt empowered and knowledgeable enough to roll back the change. Feel free to edit it if it's that ... – jcolebrand May 06 '16 at 17:46
  • ... important to you. I was trying to focus on what in the C# runtime causes a difference in behavior. I wasn't trying to ask why the logger quits working. The person in question who made the edits doesn't believe that the lack of readonly actually has the behavior I've indicated it does, and yet, I can prove it with a simple compilation test on my machine, so it evidently happens. Now, if you want to help me understand why the mechanics I listed above actually do what I show they do, I would love to understand, which is why I asked on [so] – jcolebrand May 06 '16 at 17:47
  • @jcolebrand The immediate answer to your question is obvious: a field by default is both readable and writable, but the `readonly` keyword makes it read-only, with the exception of keeping it mutable inside constructors. That's all. However, the presence of the `readonly` modifier is discoverable using reflection (where, btw, the distinction between fields and properties is very important). You have some code somewhere, possibly your own but far more likely some library, that does treat them differently. That means the libraries you're using become extremely relevant. –  May 06 '16 at 18:03
  • @jcolebrand And that's the big thing that I think was right with the edit: it focused the question on the libraries you were using. Without that focus, I don't this question as answerable, at least not in a way you'd be happy with. –  May 06 '16 at 18:07
  • @hvd so here's the thing: The question isn't "why does this framework or toolset do this thing" but rather "why doesn't the value that gets set on field initialization "stick" after the static has been initialized the first time?" If it were LightInject trying to reinitialize the ILog with a new ILog implementation every time, we would still be able to get logs at the default root logger, but we don't even get that, so that's not it. This is something about the lifetime of static that I'm not understanding fundamentally. I believe I know how it works, but I evidently don't if the value is lost – jcolebrand May 06 '16 at 18:19
  • @jcolebrand Except that it does stick, unless there's later code (from LightInject or something else) that modifies it, for instance by LightInject not only overwriting the field, but by setting it to an `ILog` instance that doesn't actually log anything. Or by later code (LightInject, Log4Net or something else) changing the Log4Net configuration. Your idea of how field initialisers work is correct. The framework and runtime don't automatically reset field value, you don't need the `readonly` keyword to stop that. –  May 06 '16 at 18:26

1 Answers1

0

Transform your variable into a Property

private static ILog _logger = LogManager.GetLogger<someType>();

public static ILog Logger {
  get{return _logger;}
  set {_logger=value;}
}

Then place a breakpoint at the set line

When the application breaks there watch the call stack

To add a further information:

  • The first time it is set, place _logger variable in the Watch Window.
  • Then right click on it and select make object id;
  • This will give you a #1 memory reference to it
  • Then add #1 to your watch list.

If, in the future, _logger stops referencing #1 it means it has changed!

Luis Filipe
  • 7,762
  • 6
  • 42
  • 72