Hi.
I came across a problem today which made me a bit confused.
I’m having two singleton objects, a loggger and an ethernethandler. The ethernethandler is using the logger instance for logging exceptions related to the ethernet connection
public sealed class Logger
{
class InternalLogger
{
static InternalLogger()
{}
internal static readonly Logger instance = new Logger();
}
public static Logger GetInstance
{
get { return InternalLogger.instance; }
}
private Logger()
{}
}
public sealed class EthernetHandler
{
public Logger Logger = Logger.GetInstance;
class InternalEthernetHandler
{
static InternalEthernetHandler()
{}
internal static readonly EthernetHandler instance = new EthernetHandler();
}
public static EthernetHandler GetInstance
{
get { return InternalEthernetHandler.instance; }
}
private EthernetHandler()
{}
}
For some reason the Logger property of the EthernetHandler is null (and stays null). Could someone explain this to me and suggest a solution.
Not sure why it isn’t working, but why do you need the internal… classes?
I usually code my singletons like this, which works fine all the time:
class MySingleton
{
public static MySingleton Instance { get; private set; }
static MySingleton()
{
new MySingleton();
}
private MySingleton()
{
// setting instance here instead of the static constructor makes sure
// the Instance is valid also for everything called by the constructor
Instance = this;
}
}
When I assume you call EthernetHandler.GetInstance some where I would say it should get called in the following order
public sealed class Logger
{
class InternalLogger
{
10 static InternalLogger()
11 {}
07 internal static readonly Logger instance = new Logger();
}
05 public static Logger GetInstance
{
06 get { return InternalLogger.instance; }
12 }
08 private Logger()
09 {}
}
public sealed class EthernetHandler
{
04 public Logger Logger = Logger.GetInstance;
class InternalEthernetHandler
{
15 static InternalEthernetHandler()
16 {}
03 internal static readonly EthernetHandler instance = new EthernetHandler();
}
01 public static EthernetHandler GetInstance
{
02 get { return InternalEthernetHandler.instance; }
}
13 private EthernetHandler()
14 {}
}
not 100%, but should be quite right.
You have to be aware that before a constructor the filed initializers are executed.
because you have 4 classes with filed initializers and static fields and constructors, it’s not obvious what is called first.
You can make your code easier to read and follow by initializing the fields inside the constructors.
Edit: And the assignment of the fileds is done after the code right of the ‘=’ is executed.
If you create an object, the filed you assigning it to is not initialized while the constructor of that class is executed!
@ olif
I agree with @ Reinhard, you are making it way too complicated.
Your static fields are part of the internal classes. This static fields are first “accessed” from the GetInstance properties of the encapsulating classes.
The static instances will be constructed right before the first GetInstance is called.
I would simplify it and move static instance one level up.
I have just tried it in Emulator and I got a valid object. Can you please show more of your code. Perhaps a complete small application that shows the problem that we can run as is.
I played around with this sample a little bit and found out the following.
NETMF seams to not recursively call static constructors.
Means when a static constructor is called it seems to create a list of all static constructors to call and does it one after the other.
If one static constructor or a subsequent call would require an other static constructor call its executed after the 1st is finished.
Now comes the crazy stuff:
The static constructors are called in alphabetical order (or it seems so).
If I rename Logger2 to ALogger2 then it static constructor is called before EthernetHandler3 static constructor and everything works as expected.
Changing the usage order or the order of the classes in file does not make a difference.
Even if you want to make sure Logger2 is executed 1st by writing something like var logger = Logger2.Instance as the 1st line in Main() it wouldn’t help because all static constructors of classes used in Main get called at the opening bracket of Main() (in alphabetical order again).
@ olif: you are right, something is wrong here.
To make sure that it works you could do as follows.
Instead of making EthernetHandler.Logger a field, make it a property
As long as you don't access Logger in constructor of EthernetHandler it works then.