Question based on two articles:

Actually, I remembered that structures have a slightly different situation with calling a static constructor (it is called before accessing a static field, but not called when creating an instance of a structure). Accordingly, there was a desire to put the Instance property inside the structure. At first, I wanted to woo something with the beauty of addressing it, but then I changed my mind and decided to ask for the very concept - does it give anything besides lazy initialization (by the way, is it really guaranteed here) and are there any side effects ?

http://ideone.com/BrgjAI

 using System; struct FieldLikeSingletonWrapper { public class FieldLikeSingleton { internal FieldLikeSingleton() { Console.WriteLine("FieldLikeSingleton.ctor"); } public void Foo() { Console.WriteLine("Foo"); } } public static FieldLikeSingleton Instance { get; } = new FieldLikeSingleton(); } class Program { static void Main(string[] args) { Console.WriteLine("Inside Main()"); if (args.Length == 42) { FieldLikeSingletonWrapper.Instance.Foo(); } } } 

By the way, at first it seemed obvious to me that making the singleton itself a structure is a terrible idea, since the structure will be copied. But then I thought that I could declare methods to throw methods through the structure (yes, this is a minus), but use the hidden nested class:

http://ideone.com/Ok1XP0

 using System; struct FieldLikeSingleton { private class FieldLikeSingletonImpl { internal FieldLikeSingletonImpl() { Console.WriteLine("FieldLikeSingleton.ctor"); } public void Foo() { Console.WriteLine("Foo"); } } private static FieldLikeSingletonImpl instance = new FieldLikeSingletonImpl(); public static FieldLikeSingleton Instance { get; } public void Foo() { instance.Foo(); } } class Program { static void Main(string[] args) { Console.WriteLine("Inside Main()"); if (args.Length == 42) { FieldLikeSingleton.Instance.Foo(); } } } 

What are the pros and cons of these approaches compared to the usual field-like?

  • four
    structures have a slightly different situation with calling a static constructor - but how? - VladD
  • 2
    @VladD, they have a static constructor called before accessing a static field. But it is not called when creating an instance of the structure :) - Qwertiy
  • one
    @Qwertiy can you add this (about the static constructor) to the question, is it nontrivial? - Vadim Ovchinnikov
  • @VadimOvchinnikov, added. - Qwertiy

1 answer 1

I remembered that structures have a slightly different situation with calling a static constructor (it is called before accessing a static field, but not called when creating an instance of a structure).

This is not quite true. More precisely, this is true if we assume that default(T) is the only way to create an instance of a structure. Yes, in the case of var x = new FooStruct() static constructor is not called, since in this case it is just the allocation and zeroing of the memory block. If, in this case, there was a type initialization check, then this would lead to significant overhead during execution (and the structures are designed specifically for such low-level scenarios where each measure has a value).

Similarly, when copying a structure, the static constructor will not be called:

 var @default = new FooStruct(); // нет вызова статического конструктора var copy = @default; // нет вызова статического конструктора 

However, when calling a custom structure constructor, the static constructor will be invoked (the same will be true for the custom constructor by default; it cannot be created in C #, but if you create it, the static constructor will also be called for var x = new FooStruct() ):

 var instance = new FooStruct(42); 

In general, here you need to understand exactly what problem you want to solve.

If the question is about the laziness of initializing a singleton, then the presence of the Instance field in the nested class will make the behavior completely lazy:

 class SomeSingleton { private class SingletonHolder { public static readonly SomeSingleton Instance = new SomeSingleton(); } public static SomeSingleton Instance => SingletonHolder.Instance; } 

In this case, accessing static members of the SomeSingleton class SomeSingleton not lead to initialization of the singleton. The only way to initialize a singleton is to call the Instance property.

I emphasize that this solution is completely lazy, but it suffers from the remaining field-like problems of singletons associated with exceptions.

PS Well, all the dances with a tambourine according to the delegation to the structure are simply redundant: it seriously complicates the accompaniment without any benefit in terms of the time of performance.

  • Thanks for the answer! Yes, something I did not think that the class will behave the same way. And what is the complication with the structure in comparison with the class? It looks like they are exactly the same. And is there really no other bonuses or pitfalls from the structures? - Qwertiy
  • The delegation has a complication for each method in that for each method of singleton you need to create a method in the shell. The second complication is a conceptual one: structures should have semantics of meaning. There is no semantics here. Overhead costs per copy are possible; the overhead of comments explaining the reason for (unclear) use of the structure is also. - Sergey Teplyakov
  • The delegation is clear - but the class has the same minus. Overhead for a copy - do not understand a copy of what? She has no fields, that is, she will not occupy more than the link. Rather, even less. Well, with semantics, yes - somewhat illogical turns out. - Qwertiy
  • Yes, there will be no overhead costs for a copy (although, in theory, the size of the structure is still not 0), but there will be costs for an additional level of indirection. For example, if without a delegation something could be inline, now it will not be inline. In a class without a delegation, there are no minuses, since the code I cited will be the same, regardless of the number of members of the singleton. - Sergey Teplyakov
  • @SergeyTeplyakov, can you see the question ? - Grundy