Singleton - if or try / catch?

I sat on this idea for quite some time and would like to hear what you guys think about it.

The standard idiom for writing a singlet is something like this:

public class A {
...
   private static A _instance;

   public static A Instance() {
      if(_instance == null) {
          _instance = new A();
      }

      return _instance;
   }
...
}

Here I propose another solution:

public class A {
...
   private static A _instance;

   public static A Instance() {
       try {
         return _instance.Self();
       } catch(NullReferenceExceptio) {
         _instance = new A();
       }           

       return _instance.Self();
   }

   public A Self() {
       return this;
   }
...
}

The basic idea is that the time taken to complete 1 dereferencing and excluded exception is less than one zero check. I tried to measure a potential increase in performance, and here are my numbers:

Sleep 1sec (try / catch): 188788ms

Sleep 1sec (nullcheck): 207485ms

And the test code:

using System;
using System.Collections.Generic;
using System.Threading;
using System.Diagnostics;

public class A
{
   private static A _instance;
   public static A Instance() {
       try {
         return _instance.Self();
       } catch(NullReferenceException) {
         _instance = new A();
       }           

       return _instance.Self();
   }

   public A Self() {
       return this;
   }

    public void DoSomething()
    {
        Thread.Sleep(1);
    }
}

public class B
{
   private static B _instance;

   public static B Instance() {
      if(_instance == null) {
          _instance = new B();
      }

      return _instance;
   }

    public void DoSomething()
    {
        Thread.Sleep(1);
    }
}

public class MyClass
{
    public static void Main()
    {
        Stopwatch sw = new Stopwatch();
        sw.Reset();

        sw.Start();
        for(int i = 0; i < 100000; ++i) {
            A.Instance().DoSomething();
        }

        Console.WriteLine(sw.ElapsedMilliseconds);
        sw.Reset();

        sw.Start();
        for(int i = 0; i < 100000; ++i) {
            B.Instance().DoSomething();
        }
        Console.WriteLine(sw.ElapsedMilliseconds);

        RL();
    }

    #region Helper methods

    private static void WL(object text, params object[] args)
    {
        Console.WriteLine(text.ToString(), args);   
    }

    private static void RL()
    {
        Console.ReadLine(); 
    }

    private static void Break() 
    {
        System.Diagnostics.Debugger.Break();
    }

    #endregion
}

10%, , , ( , , )?

+3
8

, , . #. , () , .

+17

. , , . , , , , . , , - , , - .

, , . . , , singleton #; , , . , . , ; .

. , , mainline VBScript. , ASP . , . , , .

null ref , . null ref, .

:

http://ericlippert.com/2008/09/10/vexing-exceptions/

+7

, , 10%, -, .

, . , .

" , , 97% : - ".

+6

. try/catch , , if-statement.

, . , .

+2

, , , , ( ) -.

  • DI, ? , , .
  • singleton, ? , , , , "", .

, , .

UPDATE. , , , . lock(typeof()) , .

public class A {
    private static A _instance;
    private A() { }
    public static A Instance {
        get {
            try {
                return _instance.Self();
            } catch (NullReferenceException) {
                lock (typeof(A)) {
                    if (_instance == null)
                        _instance = new A();
                }
            }
            return _instance.Self();
        }
    }
    private A Self() { return this; }
}
0

"" , , . , .

0

.

, :

 if(_instance == null) {
          _instance = new A();
      }

      return _instance;

:

return _instance ?? (_instance = new A());

.

0

:

public class A {
...
private static A _instance = new A();

public static A Instance() {
  return _instance;
}
...
}
0
source

Source: https://habr.com/ru/post/1717557/


All Articles