Main Site Documentation

.net mf clr bug?


#1

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.


#2

@ olif - Welcome to the forum!
I assume you create an instance of the Ethernet object by calling EthernetHandler.GetInstance somewhere?


#3

Hi and thank you!

Yes, you can assume that :wink:


#4

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;
   }
}

#5

It is just another way of writing singletons… I tried your suggestion and the Logger property is still null.


#6

you could put breakpoints in all constructors to see if anything is not called.
Also stepping in evertything by F11 would work.


#7

I have done that and the problem is that the Ethernernethandler gets instantiated before the logger. Shouldn’t that be handled by the clr?


#8

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!


#9

@ 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.


#10

I have implemented Reinhard:s singleton and the problem is still there.


#11

Have you checked if it’s really null, or if only the debugger is tricking you?


#12

Yes, I get a null reference exception when trying to use the logger.


#13

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.


#14

I’m using the G120.


        public static void Main()
        {
            Thread.Sleep(3 * 1000);
            var eth = EthernetHandler3.Instance;
            eth.DoWork();

            Thread.Sleep(Timeout.Infinite);
        }

        

        public class Logger2 
        {

            public static Logger2 Instance { get; private set; }

            static Logger2()
            {
                new Logger2();
            }

            private Logger2()
            {
                Instance = this;
            }

            public void AddLog()
            {
                Debug.Print("Logging");
            }
        }

        public class EthernetHandler3
        {
            public static EthernetHandler3 Instance { get; private set; }
            public Logger2 Logger = Logger2.Instance;

            static EthernetHandler3()
            {
                new EthernetHandler3();
            }

            private EthernetHandler3()
            {
                Instance = this;
            }

            public void DoWork()
            {
                Logger.AddLog();
            }
        }


#15

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.

#16

Thank you, now it´s working. Should I report this issue somewhere?


#17

You should report the issue at netmf.codeplex.com.
You could also try if it happens in the emulator as well.