1

I know other threads exist regarding this question but I couldn't find satisfactory answer for this. Why singleton class needs to be sealed in C# ? (To clarify my question)Does making it sealed really help it achieving goal of singleton (only one instance) ?

I have added more clarification about what I am wanting to know and trying to find reason for, hope readers understand what I am trying to discuss.

I am talking about MSDN article's thread safe solution : https://msdn.microsoft.com/en-us/library/ff650316.aspx.

In this article first they give solution which is not thread safe, then they give another solution using static initialization to make it thread safe and in that solution they make class: sealed

As per MSDN's explanation -- The class is marked sealed to prevent derivation, which could add instances. For a discussion of the pros and cons of marking a class sealed, see [Sells03].

When I tried to figure why they used Sealed in static initialization approach, only thing I could figure is: as they wanted to prevent additional instantiation they made it sealed (this only prevents instantiation done through derivation, nested sub class derivation could create additional instances but by using Sealed it doesn't prevent nested class from creating additional instances.) to achieve goal of singleton. If using sealed doesn't prevent additional instantiation through other ways then why use it ?

Below is the MSDN's thread safe solution:

public sealed class Singleton { private static readonly Singleton instance = new Singleton();

private Singleton(){}

public static Singleton Instance { get { return instance; } } }

My question is does MSDN's thread safe solution achieve goal of singleton by making it sealed? They made class sealed to prevent instantiation through derivation but that doesn't stop instantiation done through other ways. See my example below:

     public sealed class Singleton
     {
      private static readonly Singleton instance = new Singleton();

      private Singleton() { }

      public static Singleton Instance
      {
        get
        {
            return instance;
        }
      }

      public class nestedSingleton
      {
        public nestedSingleton()
        {
            Singleton moreThanOneObject = new Singleton();
        }
      }
    }
Learner
  • 79
  • 2
  • 11

3 Answers3

2

Simply put: if anyone can derive from it, there can be multiple instances. So you definitely need some way of preventing arbitrary derivation.

Now you can simply rely on a private constructor to prevent subclassing instead (and you need the private constructor anyway), but the only reason for making a Singleton class unsealed would be if you wanted a nested type to be the implementation, e.g.

public class Singleton
{
    public static Singleton Instance { get; }
        = (DateTime.Now.Seconds & 1) == 0
          ? (Singleton) new EvenSingleton() : new OddSingleton();

    private Singleton() {}

    private class OddSingleton : Singleton {}
    private class EvenSingleton : Singleton {}
}

This is properly a singleton - but it's a pretty unusual situation. It's vastly more common not to need a nested type to be the implementation, at which point it's clearer IMO to seal the singleton to make it clearer that you don't intend there to be any subclasses.

Basically it's communication as much as anything - a sealed class clearly prohibits derivation, whereas just having the private constructor (but no nested types) makes it more implicit. I think being explicit is clearer.

(Also, in earlier versions of C#, there are some bizarre ways you can get subclasses to compile with mutually recursive constructor calls so you never end up with a base constructor initializer. This has now been fixed, fortunately.)

To respond to a question addition:

Sealed keyword doesnt even make sense in this case if MSDN added it to prevent creating more instances of singleton by Nested sub classes.

In the example you've given, the nested class isn't a subclass. It looks like this:

public class nestedSingleton

whereas a nested subclass would look like this:

public class nestedSingleton : Singleton

(except ideally following .NET naming conventions).

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • I think the last paragraph of the question makes it clear we'd have a `private` constructor anyway, which would already prevent this. IMO it's just a matter of the MSDN documentation being a bit muddy. – Jon Apr 17 '16 at 19:29
  • @Jon: Frankly I find the question a bit hard to parse, but yes, it's feasible - I've updated the answer. – Jon Skeet Apr 17 '16 at 19:30
  • OddSingleton and EvenSingleton is really *odd* :) – Sriram Sakthivel Apr 17 '16 at 19:32
  • @Jon, this does't asnwer my question. I have added more clarification and details to my question. – Learner Apr 18 '16 at 18:28
  • @Learner: I think it does answer the question: no, the class doesn't have to be sealed, but sealing it if you *don't* need a nested subclass helps to communicate the fact that you're not expecting anyone to even *try* to derive from it. Note that the nested class in your example isn't a subclass of `Singleton`, so it's fine for `Singleton` to be sealed. – Jon Skeet Apr 18 '16 at 18:31
  • @Learner: I'd also suggest that you edit the question a bit more. The code is all badly formatted, and it's not clear where you got that nested class example from, given that it's not from the MSDN page you referred to. – Jon Skeet Apr 18 '16 at 18:34
  • I added more explanation and clarification about what I am asking. I know my nested class: public class nestedSingleton isn't inheriting from Singleton as I wanted to show that Sealed doesn't make sense in this case if MSDN is claiming that making it sealed would prevent further instantiaion. Of course sealed would prevent nested sub classes to be created thus not letting them create instance of singleton but what about nested class which is not deriving from singleton at all but still creating instance of Singleton ? – Learner Apr 18 '16 at 18:47
  • @Learner: Well that has to be within the program text of `Singleton`, and would therefore be assumed to be trusted. If you knew that the nested class wasn't a subclass, why say it *was* a subclass? That's confusing. Now, `sealed` doesn't prevent instantiation - it *only* prevents derivation. However, it communicates clearly that the class is not intended to be derived from, whereas a private constructor makes it much less obvious. I don't see why you think MSDN is talking about nested classes at all though - the word "nested" doesn't appear. – Jon Skeet Apr 18 '16 at 18:50
  • @Learner: Additionally, your question is *still* badly formatted. Please read http://stackoverflow.com/editing-help – Jon Skeet Apr 18 '16 at 18:51
  • @Jon Skeet thanks for your response, what I asked is MSDN is saying they used sealed to prevent instantiation (they didnt say what type of instantion they are referring to so I assumed they are referring to instantiation done through nested subclass as non nested classes can't inherit from singleton at all. That is my guess that MSDN is using sealed to prevent instantiation through nested subclasses as that is the only other option where Sealed would prevent them but my question is sealed only prevents nested sub classes but nested classes can still create more instances ) – Learner Apr 18 '16 at 18:57
  • @Learner: It doesn't say that. It says "The class is marked sealed to prevent derivation, which could add instances". Derivation != instantiation. If there were any derived classes, *they* could have public constructors... – Jon Skeet Apr 18 '16 at 18:59
  • @Jon Skeet, I understand Derivation != instantiation, but the purpose of preventing derivation was to prevent instantiation (no more than one instance of singleton) through nested subclasses (that is the only possible way in case of derivation). Does that solution (making it sealed) address preventing creation of more instances through nested classes ? If making it Sealed doesn't address preventing further instantiation in all ways then why make class Sealed (which only prevents instantiation through nested subclasses) as we can still create instances through nested classes ? – Learner Apr 18 '16 at 19:16
  • @Learner: I'm afraid I think I've given the answer to that as many times as I can stand to. Note that MSDN doesn't mention nested classes anywhere, so I wouldn't assume the author of that article had them in mind at all. – Jon Skeet Apr 18 '16 at 19:33
1

It does not have to be

Implementing Singleton in C#

This is not safe on multithreads but a singleton

public class Singleton
{
   private static Singleton instance;

   private Singleton() {}

   public static Singleton Instance
   {
      get 
      {
         if (instance == null)
         {
            instance = new Singleton();
         }
         return instance;
      }
   }
}

Making it sealed would make it not possible to inherit it (eliminating a possible cause for several instances of a singleton)

Thomas Andreè Wang
  • 3,379
  • 6
  • 37
  • 53
  • exactly. The thing is, sealed only prevents derivations of the class. – Thomas Andreè Wang Apr 17 '16 at 19:24
  • It doesn't have to be sealed. But marking the constructor private is essentially equal to sealed. – Sriram Sakthivel Apr 17 '16 at 19:24
  • The point of the question, is why does it have to be sealed? well it does not have to be. all OP needs to do is to read up on sealed and what it does. (iI' assuming he has, so the next question is, it does not have to be but there are pitfalls with that) That's why the link is there to MS Design & Patterns detailing why sealed is in use. – Thomas Andreè Wang Apr 17 '16 at 19:27
  • @Thomas, this does't asnwer my question. I have added more clarification and details to my question. I am already talking about thread safe solution from MSDN article – Learner Apr 18 '16 at 18:29
-3

The reason is very tied to implementation details.

For example, see the following simple and wrong singleton implementation in C#:

public class A 
{
     private static readonly A _instance;

     static A() 
     {
         _instance = new A();
     }

     public static A Instance => _instance;

     public string Name { get; set; }
}

Now let's derive it into B:

public class B : A 
{
    public string Surname { get; set; }
}

What would happen if you call B.Current static property?

// ERROR! Surname isn't a property of A
string surname = B.Instance.Surname; 

One of main drawbacks of not sealing a singleton class is that static members are still accessible on derived classes. That is, it's very confusing that you can access Instance property on B but it returns the singleton instance of A.

You can't take this risk and one simple and yet powerful way of avoiding confusion is sealing A. Since A is a singleton implementation, you don't want to be inheritable, because derived classes can't expand the singleton.

If you're agree with the point of avoiding the described situation, a more convenient implementation of singleton could be:

// SEALED
public sealed class A 
{
     private static readonly A _instance;

     // Avoid that other code excepting A class members
     // can instantiate A
     private A() {}

     static A() 
     {
         _instance = new A();
     }

     public static A Instance => _instance;

     public string Name { get; set; }
}

About the criticism of using a static read-only field instead of lazy-loading the single instance...

I've also checked that some seem to be against my proposal of instantiating the single instance as part of static constructor or using a field initializer. I could also simplify the implementation as follows:

public sealed class A 
{
     private A() {}

     private static readonly A _instance = new A();

     public static A Instance => _instance;
     public string Name { get; set; }
}

And, as far as I know, it provides more advantages than instantiating the single A instance in the Instance static property getter:

...

private static A _instance;

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

         return _instance;
    }
}

See this other Q&A to understand that static constructors are thread-safe: Is the C# static constructor thread safe?

In response to my answer's criticism about my sample singleton implementation

In some comment, Jon Skeet has said:

A singleton doesn't just provide a single instance - it ensure that it's the only instance ever created. See en.wikipedia.org/wiki/Singleton_pattern "In software engineering, the singleton pattern is a design pattern that restricts the instantiation of a class to one object." Your code doesn't do that.

It's not a good argument to invalidate my sample implementation. For example, most inversion of control containers let you configure the life-cycle to singleton of a given component and its implementation.

The whole implementation is a regular public class with no constraint preventing you from even configuring the same implementation for other component, or you can even instantiate the implementation with new (i.e. new A()) wherever you want.

But the so-called component is a singleton, because you've configured that it will be a single instance of the whole component across the entire AppDomain.

Now let's see the Implementation section on Singleton pattern (Wikipedia):

Implementation of a singleton pattern must satisfy the single instance and global access principles. It requires a mechanism to access the singleton class member without creating a class object and a mechanism to persist the value of class members among class objects. The singleton pattern is implemented by creating a class with a method that creates a new instance of the class if one does not exist. If an instance already exists, it simply returns a reference to that object. To make sure that the object cannot be instantiated any other way, the constructor is made private. Note the distinction between a simple static instance of a class and a singleton: although a singleton can be implemented as a static instance, it can also be lazily constructed, requiring no memory or resources until needed.

Comparing this implementation description with my sample implementation, I would say that the following implementation is a singleton:

public sealed class A 
{
     private A() {}

     private static readonly A _instance = new A();

     public static A Instance => _instance;
     public string Name { get; set; }
}
  1. You can't publicly instantiate it.
  2. It can be only a single instance within a given AppDomain.
  3. It provides global access to itself.
  4. It implements a method to create the single instance, but it's using C# specific syntax and syntactic sugar.
  5. It's lazily instantiated when the static Instance property is first instantiated. This is how static constructors and static class field initializers work in C#.

Now let's analyze the inversion of control container case:

  1. Usually components are defined by interfaces and abstract classes. Few times are concrete classes. Thus, you can't instantiate an abstract class or interface.
  2. There's no Instance static property, but the implementation description on Wikipedia says: [...] It requires a mechanism to access the singleton class member without creating a class object and a mechanism to persist the value of class members among class objects. The fact that you can implement this with an Instance static property of singleton class is just an implementation detail on some programming languages. The pattern description is fine with how inversion of control containers work. Either something like service locator anti-pattern or just dependency injection, are mechanisms that provide the single instance.
  3. With inversion of control containers you can access singletons globally. For example, Container.Resolve<ISomeComponentConfiguredAsSingleton>(). BTW, excepting on few cases, service locator is considered an anti-pattern.
  4. Most inversion of control containers can provide custom factories where you can define how the component implementation will be instantiated.
  5. Based on previous point, you can easily implement a factory with lazy-loading.

In summary, I would say that in my particular case I've already left my ortodoxy and I assume that design patterns are abstract definitions to implement solutions to common problems and most are and should be language-agnostic. As long as my code works as the description of a given design pattern for me is enough to consider I'm implementing the whole design pattern. You can even implement singleton without calling your class WhateverSingleton.

Community
  • 1
  • 1
Matías Fidemraizer
  • 63,804
  • 18
  • 124
  • 206
  • 1
    *For example, see the following simple singleton implementation in C#:* That's not a singleton. Your class just exposes a static instance. – Sriram Sakthivel Apr 17 '16 at 19:26
  • 1
    I don't see what all of this has to do with singletons. And of course you *have* to assume private constructor (which would prevent inheritance) otherwise it's not a singleton by any stretch of the imagination. – Jon Apr 17 '16 at 19:26
  • @SriramSakthivel Static constructors are a good way of initializing static class fields, aren't they? If you need to be sure that there's a single instance in the given `AppDomain`, you'll need to convince me that I'm wrong when I use a static constructor and I set a `readonly` field... – Matías Fidemraizer Apr 17 '16 at 19:28
  • @Jon I hate this kind of bold statements. The fact I didn't implemented a private instance constructor doesn't destroy the point of avoiding the situation I've described in my answer. – Matías Fidemraizer Apr 17 '16 at 19:30
  • My point isn't about initializing. Singleton implementation should almost create single instance. Where in your code you do it? Anyone can create any number of instances of `A`. Like so `new A()` – Sriram Sakthivel Apr 17 '16 at 19:30
  • @MatíasFidemraizer: I don't particularly care if you *hate* that statement, because hate is subjective. I would very much care if you agreed with or logically countered it instead. – Jon Apr 17 '16 at 19:31
  • @MatíasFidemraizer: The code you've provided just isn't a singleton... it's as simple as that. Unless you prevent other code from instantiating it, you don't have a singleton. – Jon Skeet Apr 17 '16 at 19:32
  • @SriramSakthivel I've fixed this. And I'm with you that code constraints are better than coding conventions. If I consider a class a singleton, I wouldn't instantiate it myself somewhere, but as you can already check in my updated answer, I've added the whole private constructor to `A` to prevent that use case.. – Matías Fidemraizer Apr 17 '16 at 19:32
  • @MatíasFidemraizer: Now that you added a private `A` constructor, the definition of `B` does not compile. So where does this leave the answer? – Jon Apr 17 '16 at 19:33
  • @MatíasFidemraizer: That also prevents `B` from compiling, unless it's a nested type... and given that it's public, you could still have `A a1 = new B(); A a2 = new B();` - how is it a singleton? – Jon Skeet Apr 17 '16 at 19:33
  • @JonSkeet Why? I don't see why it's not a singleton. See the other answer, what it's extremely different? The other answer instantiate the *single instance* in the `Instance` property getter. – Matías Fidemraizer Apr 17 '16 at 19:34
  • @MatíasFidemraizer: A singleton doesn't just *provide* a single instance - it ensure that it's the *only* instance ever created. See https://en.wikipedia.org/wiki/Singleton_pattern "In software engineering, the singleton pattern is a design pattern that restricts the instantiation of a class to one object." Your code doesn't do that. – Jon Skeet Apr 17 '16 at 19:34
  • Now your class `B` won't even compile --which invalidates all of your answer. – Sriram Sakthivel Apr 17 '16 at 19:35
  • @SriramSakthivel I've removed the private construtor. I shouldn't edit my answers without thinking what I'm going to do before. – Matías Fidemraizer Apr 17 '16 at 19:36
  • @MatíasFidemraizer You're in "Chicken and Egg problem now". Your answer no more talks about a singleton. – Sriram Sakthivel Apr 17 '16 at 19:38
  • @JonSkeet With all respects, because I consider you're a very wise person on this field. But, then, do you consider that an inversion of control life-cycle management set to *singleton* when the implementation is just a public class, isn't a singleton? – Matías Fidemraizer Apr 17 '16 at 19:38
  • @MatíasFidemraizer: It's not a singleton in the normal way, no. It's not the singleton pattern. It's trying to achieve a similar effect without actually being a singleton. Note that in the singleton pattern, the "singleton-ness" is inherent in the class itself, not the use of it. – Jon Skeet Apr 17 '16 at 19:46
  • @JonSkeet If we need to talk about singleton pattern, we can also talk that it can be implemented in languages where there're no access modifiers. Do you still consider that not being able to constraint the singleton class to avoid its public instantiation invalidates the entire design pattern? We need to be more flexible... BTW, it's just my opinion. – Matías Fidemraizer Apr 17 '16 at 19:51
  • I've edited my answer with more details, and answers to your concerns... I believe I'm not that wrong, but sadly there's too much ortodoxy today. – Matías Fidemraizer Apr 17 '16 at 20:01
  • @MatíasFidemraizer: Yes, at that point I don't think you can say you're implementing the singleton pattern. You can decide to *use* something in a single instance way, but that's *not* the singleton pattern, and it's not a singleton class. Note how the MSDN article referenced, the wikipedia article, and basically *every bit of terminology used by everyone other than you* is about the same concept: a class which prevents multiple instances from being created. Given that one purpose of giving names to design patterns is to avoid confusion, why conflate the two ideas? – Jon Skeet Apr 17 '16 at 20:05
  • @JonSkeet If you see my edited answer, where I propose a more convenient implementation, it has all to be a singleton. – Matías Fidemraizer Apr 17 '16 at 20:09
  • @JonSkeet IMHO, you've concentrated your effort on the sample singleton implementation in my answer, and not only you, but other people that has commented out to criticize this part has forgotten that the issue I've described in my answer exists if you don't seal the singleton class. – Matías Fidemraizer Apr 17 '16 at 20:11
  • @MatíasFidemraizer: I'm afraid I find your answer very hard to understand now as it jumps around all over the place, and a lot of it is about classes which simply *aren't singletons*. Take your very first class, introduced with "For example, see the following simple singleton implementation in C#" - but I can call `A a1 = new A(); A2 = new A();`, therefore it is not a singleton class as understood by everyone else involved in the question (and by the wikipedia and MSDN definitions). – Jon Skeet Apr 17 '16 at 20:12
  • @JonSkeet BTW, sadly, answer's comments aren't the best place to extensively discuss the implementation of some design patten. I'll try to post in my unknown and humble blog why I consider my sample implementation to be the singleton pattern, requirement by requirement described by the pattern itself... – Matías Fidemraizer Apr 17 '16 at 20:13
  • @JonSkeet That first implementation you mention is wrong. Who's discussing that? I tried to be in the skin of the OP and give the OP a sample implementation of a wrong singleton using inheritance. That's all. – Matías Fidemraizer Apr 17 '16 at 20:14
  • Well if you know the first example isn't a singleton implementation, you should remove it from the answer. How is anyone meant to know which bits of your answer you still believe in and which you don't? The problem with is much earlier than B.Current... You don't need to derive from it at all to break the singleton-ness... – Jon Skeet Apr 17 '16 at 20:21
  • @JonSkeet Because I say in the whole answer that it's wrong. I'll edit to make it clearer – Matías Fidemraizer Apr 17 '16 at 20:56
  • But you haven't addressed the fact that you've done two things: made it a sealed class *and* added a private constructor. Making the constructor private is required - making the class sealed is not, strictly speaking. I think it's worth doing, but it's not necessary. Further, your digression into what makes something a singleton feels like it's irrelevant to the question asked, which is clearly referring to the classic definition of a singleton class / the singleton pattern, rather than the DI style singleton *usage*, which is very different. – Jon Skeet Apr 17 '16 at 21:07
  • Well I'm done here, I'm afraid. This will be my last comment on this answer. – Jon Skeet Apr 17 '16 at 21:11
  • @JonSkeet This is up to you, I'm not editing the answer for you, it's just I want to contribute my point on the topic. I've already edited with a lot of details that I really believe that may not add any value to the OP but it can assist him and also downvoters to understand my point of view. – Matías Fidemraizer Apr 17 '16 at 21:28