Singleton Design Pattern implementation in a not traditional wayResourceManager SingletonCorrect way to...
Round towards zero
Handling Disruptive Student on the Autistic Spectrum
Is gzip atomic?
Prove your innocence
Is there any example of one country devastating a third?
Is a player able to change alignment midway through an adventure?
A discontinuity in an integral
How do I request a longer than normal leave of absence period for my wedding?
Justifying the use of directed energy weapons
Why did MS-DOS applications built using Turbo Pascal fail to start with a division by zero error on faster systems?
Is there any way to keep a player from killing an NPC?
What is a CirKle Word™?
Architectural feasibility of a tiered circular stone keep
How do you harvest carrots in creative mode?
Is there any music source code for sound chips?
I don't have the theoretical background in my PhD topic. I can't justify getting the degree
Who was president of the USA?
SQL Server Management Studio - Why is Dark Theme Disabled by Default?
Nothing like a good ol' game of ModTen
LeetCode: Group Anagrams C#
Numbers Decrease while Letters Increase
How many US airports have 4 or more parallel runways?
Strange-looking FM transmitter circuit
Non-visual Computers - thoughts?
Singleton Design Pattern implementation in a not traditional way
ResourceManager SingletonCorrect way to implement a Singleton fieldBuilding in the built-in declarationsSingleton Class for WordPress PluginThrowing exception in the singleton pattern in C#Singleton manager/service classes with mockable dependencies in swiftSimple builder pattern implementation for building immutable objectsSingleton Pattern + unavoidable Public Constructor
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ margin-bottom:0;
}
$begingroup$
For implementing Singleton
we can use Traditional way like this Article,
but i think that to write it in another way:
public class Person
{
private static Person personInstance;
static Person()
{
personInstance = new Person();
}
private Person() { }
public static Person GetPersonInstance()
{
return personInstance;
}
}
As we know a Static Constructor
will call automatically before the first instance is created or any static members are referenced and just once only. so if i write singleton like above, is it true (i mean this class is singleton)? or not?
c# design-patterns singleton
New contributor
$endgroup$
add a comment |
$begingroup$
For implementing Singleton
we can use Traditional way like this Article,
but i think that to write it in another way:
public class Person
{
private static Person personInstance;
static Person()
{
personInstance = new Person();
}
private Person() { }
public static Person GetPersonInstance()
{
return personInstance;
}
}
As we know a Static Constructor
will call automatically before the first instance is created or any static members are referenced and just once only. so if i write singleton like above, is it true (i mean this class is singleton)? or not?
c# design-patterns singleton
New contributor
$endgroup$
3
$begingroup$
csharpindepth.com/articles/singleton. Jon Skeet article on singleton. It's some kind of cannonical read before starting any conversation about singleton.
$endgroup$
– xdtTransform
23 hours ago
$begingroup$
I can't deal with the capitalization ofSingleTonSample
in the article OP posted.
$endgroup$
– JPhi1618
15 hours ago
add a comment |
$begingroup$
For implementing Singleton
we can use Traditional way like this Article,
but i think that to write it in another way:
public class Person
{
private static Person personInstance;
static Person()
{
personInstance = new Person();
}
private Person() { }
public static Person GetPersonInstance()
{
return personInstance;
}
}
As we know a Static Constructor
will call automatically before the first instance is created or any static members are referenced and just once only. so if i write singleton like above, is it true (i mean this class is singleton)? or not?
c# design-patterns singleton
New contributor
$endgroup$
For implementing Singleton
we can use Traditional way like this Article,
but i think that to write it in another way:
public class Person
{
private static Person personInstance;
static Person()
{
personInstance = new Person();
}
private Person() { }
public static Person GetPersonInstance()
{
return personInstance;
}
}
As we know a Static Constructor
will call automatically before the first instance is created or any static members are referenced and just once only. so if i write singleton like above, is it true (i mean this class is singleton)? or not?
c# design-patterns singleton
c# design-patterns singleton
New contributor
New contributor
edited 2 days ago
pejman
New contributor
asked 2 days ago
pejmanpejman
1835 bronze badges
1835 bronze badges
New contributor
New contributor
3
$begingroup$
csharpindepth.com/articles/singleton. Jon Skeet article on singleton. It's some kind of cannonical read before starting any conversation about singleton.
$endgroup$
– xdtTransform
23 hours ago
$begingroup$
I can't deal with the capitalization ofSingleTonSample
in the article OP posted.
$endgroup$
– JPhi1618
15 hours ago
add a comment |
3
$begingroup$
csharpindepth.com/articles/singleton. Jon Skeet article on singleton. It's some kind of cannonical read before starting any conversation about singleton.
$endgroup$
– xdtTransform
23 hours ago
$begingroup$
I can't deal with the capitalization ofSingleTonSample
in the article OP posted.
$endgroup$
– JPhi1618
15 hours ago
3
3
$begingroup$
csharpindepth.com/articles/singleton. Jon Skeet article on singleton. It's some kind of cannonical read before starting any conversation about singleton.
$endgroup$
– xdtTransform
23 hours ago
$begingroup$
csharpindepth.com/articles/singleton. Jon Skeet article on singleton. It's some kind of cannonical read before starting any conversation about singleton.
$endgroup$
– xdtTransform
23 hours ago
$begingroup$
I can't deal with the capitalization of
SingleTonSample
in the article OP posted.$endgroup$
– JPhi1618
15 hours ago
$begingroup$
I can't deal with the capitalization of
SingleTonSample
in the article OP posted.$endgroup$
– JPhi1618
15 hours ago
add a comment |
2 Answers
2
active
oldest
votes
$begingroup$
Your implementation does the trick. For what it's worth, I would consider your implementation the current "traditional way". It is thread-safe. The static constructor is guaranteed to run only once, so you won't accidentally end up with two instances if two threads try to grab the instance for the first time simultaneously.
Laziness
There is one more thing you might want to consider though. Because of the way the static constructor works, it is executed the first time the class is referenced in the code. This means that the instance in your singleton is created, even when you don't try to grab the instance, but another static variable perhaps.
To fix this, you might want to make the creation of the instance lazy, so that it really only fires when you need it. To do this, you can use the Lazy<T>
class.
Sealed
This is mostly a formality, but it's nice when trying to do it formally. The sealed
keyword means that that class cannot be inherited from. The private constructor already ensured that, but this makes it more explicit.
Readonly
As Jesse mentioned in the comments, it's a good idea to make the instance field (lazy or not) readonly
. This prevents you from accidentally mucking up your singleton instance from within the class.
public sealed class Person
{
private Person() { }
private static readonly Lazy<Person> lazyPersonInstance = new Lazy<Person>(() => new Person());
public static Person GetPersonInstance()
{
return lazyPersonInstance.Value;
}
}
Your method GetPersonInstance
can also be a getter-property:
public static Person Instance => lazyPersonInstance.Value;
Exceptions
IEatBagels already posted an answer about throwing exceptions. I'll elaborate a bit on how it would work in this example. We're looking at the scenario where instantiating the singleton instance throws an exception.
In your code, this exception would be thrown when the static constructor is ran. As IEatBagels points out, when this happens, the type is broken for the rest of the "program". This means that you have one shot at creating your instance.
In my example, the initiation of the instance does not happen during the execution of the static constructor. All we do during static initialization - static constructor and static fields act similarly IIRC - is creating the Lazy<T>
object with the factory method. This method is only executed when lazyPersonInstance.Value
is called.
However, Lazy<T>
caches exceptions. This means that if the factory method throws an exception, that exception will be rethrown on every subsequent call to lazyPersonInstance.Value
. Without re-executing the factory method. So in the end, this is the same problem as the static constructor problem. The Lazy<T>
docs have the following to say:
The Lazy stands in for an actual T that otherwise would have been initialized at some earlier point, usually during startup. A failure at that earlier point is usually fatal. If there is a potential for a recoverable failure, we recommend that you build the retry logic into the initialization routine (in this case, the factory method), just as you would if you weren't using lazy initialization.
MSDN docs
So if you really must throw exceptions in your constructor, be sure to handle them in the factory method.
Exceptions and thread-safety
There's one more workaround for the problem of exceptions in constructors. Lazy
has three thread-safety modes, defined in the enum System.Threading.LazyThreadSafetyMode
which can be passed to the constructor of Lazy<T>
.
None
. No thread safety.
ExecutionAndPublication
. This is the default. This ensures that the factory method is executed only once, and that the object onlazy.Value
is always the same across threads.
PublicationOnly
. This only ensures thread-safety onlazy.Value
. It can happen that the factory method is executed simultaneously by multiple threads, but the resulting instance is still the same. The others are discarded. According to theLazy<T>
docs, Exceptions are not cached here.
This leaves you, the implementer of the singleton with a decision: if there are exceptions that might be thrown, that can't be handled within the factory method, and that might not throw in subsequent attempts (weird, but might happen), you could consider loosening up some of the locking on Lazy
to allow for this behaviour.
For further reading, see this blog post by Jon Skeet.
$endgroup$
4
$begingroup$
One small note - to truly be a singleton, the class should also besealed
so no inheritors can be created and change behavior.
$endgroup$
– Jesse C. Slicer
yesterday
4
$begingroup$
@jessecslicer hmm, I was going to mention that, but the private constructor already prevents inheritance. It's never a bad idea though.
$endgroup$
– JAD
yesterday
5
$begingroup$
I'd probably also marklazyPersonInstance
asreadonly
to keep other methods from being able to muck around with it, even by accident.
$endgroup$
– Jesse C. Slicer
yesterday
1
$begingroup$
@JesseC.Slicer thanks, added :)
$endgroup$
– JAD
yesterday
add a comment |
$begingroup$
There's a potential bug with this scenario.
According to this Jon Skeet post, if an exception is thrown inside the static
constructor, it is never retried. Which means that if your Singleton initialization has a problem, your Singleton is doomed for the lifetime of your application, which normally isn't a problem with the "traditional" way of doing it.
$endgroup$
$begingroup$
good catch. real world (constructors) vs academic examples.
$endgroup$
– granadaCoder
16 hours ago
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "196"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
pejman is a new contributor. Be nice, and check out our Code of Conduct.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f226611%2fsingleton-design-pattern-implementation-in-a-not-traditional-way%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
$begingroup$
Your implementation does the trick. For what it's worth, I would consider your implementation the current "traditional way". It is thread-safe. The static constructor is guaranteed to run only once, so you won't accidentally end up with two instances if two threads try to grab the instance for the first time simultaneously.
Laziness
There is one more thing you might want to consider though. Because of the way the static constructor works, it is executed the first time the class is referenced in the code. This means that the instance in your singleton is created, even when you don't try to grab the instance, but another static variable perhaps.
To fix this, you might want to make the creation of the instance lazy, so that it really only fires when you need it. To do this, you can use the Lazy<T>
class.
Sealed
This is mostly a formality, but it's nice when trying to do it formally. The sealed
keyword means that that class cannot be inherited from. The private constructor already ensured that, but this makes it more explicit.
Readonly
As Jesse mentioned in the comments, it's a good idea to make the instance field (lazy or not) readonly
. This prevents you from accidentally mucking up your singleton instance from within the class.
public sealed class Person
{
private Person() { }
private static readonly Lazy<Person> lazyPersonInstance = new Lazy<Person>(() => new Person());
public static Person GetPersonInstance()
{
return lazyPersonInstance.Value;
}
}
Your method GetPersonInstance
can also be a getter-property:
public static Person Instance => lazyPersonInstance.Value;
Exceptions
IEatBagels already posted an answer about throwing exceptions. I'll elaborate a bit on how it would work in this example. We're looking at the scenario where instantiating the singleton instance throws an exception.
In your code, this exception would be thrown when the static constructor is ran. As IEatBagels points out, when this happens, the type is broken for the rest of the "program". This means that you have one shot at creating your instance.
In my example, the initiation of the instance does not happen during the execution of the static constructor. All we do during static initialization - static constructor and static fields act similarly IIRC - is creating the Lazy<T>
object with the factory method. This method is only executed when lazyPersonInstance.Value
is called.
However, Lazy<T>
caches exceptions. This means that if the factory method throws an exception, that exception will be rethrown on every subsequent call to lazyPersonInstance.Value
. Without re-executing the factory method. So in the end, this is the same problem as the static constructor problem. The Lazy<T>
docs have the following to say:
The Lazy stands in for an actual T that otherwise would have been initialized at some earlier point, usually during startup. A failure at that earlier point is usually fatal. If there is a potential for a recoverable failure, we recommend that you build the retry logic into the initialization routine (in this case, the factory method), just as you would if you weren't using lazy initialization.
MSDN docs
So if you really must throw exceptions in your constructor, be sure to handle them in the factory method.
Exceptions and thread-safety
There's one more workaround for the problem of exceptions in constructors. Lazy
has three thread-safety modes, defined in the enum System.Threading.LazyThreadSafetyMode
which can be passed to the constructor of Lazy<T>
.
None
. No thread safety.
ExecutionAndPublication
. This is the default. This ensures that the factory method is executed only once, and that the object onlazy.Value
is always the same across threads.
PublicationOnly
. This only ensures thread-safety onlazy.Value
. It can happen that the factory method is executed simultaneously by multiple threads, but the resulting instance is still the same. The others are discarded. According to theLazy<T>
docs, Exceptions are not cached here.
This leaves you, the implementer of the singleton with a decision: if there are exceptions that might be thrown, that can't be handled within the factory method, and that might not throw in subsequent attempts (weird, but might happen), you could consider loosening up some of the locking on Lazy
to allow for this behaviour.
For further reading, see this blog post by Jon Skeet.
$endgroup$
4
$begingroup$
One small note - to truly be a singleton, the class should also besealed
so no inheritors can be created and change behavior.
$endgroup$
– Jesse C. Slicer
yesterday
4
$begingroup$
@jessecslicer hmm, I was going to mention that, but the private constructor already prevents inheritance. It's never a bad idea though.
$endgroup$
– JAD
yesterday
5
$begingroup$
I'd probably also marklazyPersonInstance
asreadonly
to keep other methods from being able to muck around with it, even by accident.
$endgroup$
– Jesse C. Slicer
yesterday
1
$begingroup$
@JesseC.Slicer thanks, added :)
$endgroup$
– JAD
yesterday
add a comment |
$begingroup$
Your implementation does the trick. For what it's worth, I would consider your implementation the current "traditional way". It is thread-safe. The static constructor is guaranteed to run only once, so you won't accidentally end up with two instances if two threads try to grab the instance for the first time simultaneously.
Laziness
There is one more thing you might want to consider though. Because of the way the static constructor works, it is executed the first time the class is referenced in the code. This means that the instance in your singleton is created, even when you don't try to grab the instance, but another static variable perhaps.
To fix this, you might want to make the creation of the instance lazy, so that it really only fires when you need it. To do this, you can use the Lazy<T>
class.
Sealed
This is mostly a formality, but it's nice when trying to do it formally. The sealed
keyword means that that class cannot be inherited from. The private constructor already ensured that, but this makes it more explicit.
Readonly
As Jesse mentioned in the comments, it's a good idea to make the instance field (lazy or not) readonly
. This prevents you from accidentally mucking up your singleton instance from within the class.
public sealed class Person
{
private Person() { }
private static readonly Lazy<Person> lazyPersonInstance = new Lazy<Person>(() => new Person());
public static Person GetPersonInstance()
{
return lazyPersonInstance.Value;
}
}
Your method GetPersonInstance
can also be a getter-property:
public static Person Instance => lazyPersonInstance.Value;
Exceptions
IEatBagels already posted an answer about throwing exceptions. I'll elaborate a bit on how it would work in this example. We're looking at the scenario where instantiating the singleton instance throws an exception.
In your code, this exception would be thrown when the static constructor is ran. As IEatBagels points out, when this happens, the type is broken for the rest of the "program". This means that you have one shot at creating your instance.
In my example, the initiation of the instance does not happen during the execution of the static constructor. All we do during static initialization - static constructor and static fields act similarly IIRC - is creating the Lazy<T>
object with the factory method. This method is only executed when lazyPersonInstance.Value
is called.
However, Lazy<T>
caches exceptions. This means that if the factory method throws an exception, that exception will be rethrown on every subsequent call to lazyPersonInstance.Value
. Without re-executing the factory method. So in the end, this is the same problem as the static constructor problem. The Lazy<T>
docs have the following to say:
The Lazy stands in for an actual T that otherwise would have been initialized at some earlier point, usually during startup. A failure at that earlier point is usually fatal. If there is a potential for a recoverable failure, we recommend that you build the retry logic into the initialization routine (in this case, the factory method), just as you would if you weren't using lazy initialization.
MSDN docs
So if you really must throw exceptions in your constructor, be sure to handle them in the factory method.
Exceptions and thread-safety
There's one more workaround for the problem of exceptions in constructors. Lazy
has three thread-safety modes, defined in the enum System.Threading.LazyThreadSafetyMode
which can be passed to the constructor of Lazy<T>
.
None
. No thread safety.
ExecutionAndPublication
. This is the default. This ensures that the factory method is executed only once, and that the object onlazy.Value
is always the same across threads.
PublicationOnly
. This only ensures thread-safety onlazy.Value
. It can happen that the factory method is executed simultaneously by multiple threads, but the resulting instance is still the same. The others are discarded. According to theLazy<T>
docs, Exceptions are not cached here.
This leaves you, the implementer of the singleton with a decision: if there are exceptions that might be thrown, that can't be handled within the factory method, and that might not throw in subsequent attempts (weird, but might happen), you could consider loosening up some of the locking on Lazy
to allow for this behaviour.
For further reading, see this blog post by Jon Skeet.
$endgroup$
4
$begingroup$
One small note - to truly be a singleton, the class should also besealed
so no inheritors can be created and change behavior.
$endgroup$
– Jesse C. Slicer
yesterday
4
$begingroup$
@jessecslicer hmm, I was going to mention that, but the private constructor already prevents inheritance. It's never a bad idea though.
$endgroup$
– JAD
yesterday
5
$begingroup$
I'd probably also marklazyPersonInstance
asreadonly
to keep other methods from being able to muck around with it, even by accident.
$endgroup$
– Jesse C. Slicer
yesterday
1
$begingroup$
@JesseC.Slicer thanks, added :)
$endgroup$
– JAD
yesterday
add a comment |
$begingroup$
Your implementation does the trick. For what it's worth, I would consider your implementation the current "traditional way". It is thread-safe. The static constructor is guaranteed to run only once, so you won't accidentally end up with two instances if two threads try to grab the instance for the first time simultaneously.
Laziness
There is one more thing you might want to consider though. Because of the way the static constructor works, it is executed the first time the class is referenced in the code. This means that the instance in your singleton is created, even when you don't try to grab the instance, but another static variable perhaps.
To fix this, you might want to make the creation of the instance lazy, so that it really only fires when you need it. To do this, you can use the Lazy<T>
class.
Sealed
This is mostly a formality, but it's nice when trying to do it formally. The sealed
keyword means that that class cannot be inherited from. The private constructor already ensured that, but this makes it more explicit.
Readonly
As Jesse mentioned in the comments, it's a good idea to make the instance field (lazy or not) readonly
. This prevents you from accidentally mucking up your singleton instance from within the class.
public sealed class Person
{
private Person() { }
private static readonly Lazy<Person> lazyPersonInstance = new Lazy<Person>(() => new Person());
public static Person GetPersonInstance()
{
return lazyPersonInstance.Value;
}
}
Your method GetPersonInstance
can also be a getter-property:
public static Person Instance => lazyPersonInstance.Value;
Exceptions
IEatBagels already posted an answer about throwing exceptions. I'll elaborate a bit on how it would work in this example. We're looking at the scenario where instantiating the singleton instance throws an exception.
In your code, this exception would be thrown when the static constructor is ran. As IEatBagels points out, when this happens, the type is broken for the rest of the "program". This means that you have one shot at creating your instance.
In my example, the initiation of the instance does not happen during the execution of the static constructor. All we do during static initialization - static constructor and static fields act similarly IIRC - is creating the Lazy<T>
object with the factory method. This method is only executed when lazyPersonInstance.Value
is called.
However, Lazy<T>
caches exceptions. This means that if the factory method throws an exception, that exception will be rethrown on every subsequent call to lazyPersonInstance.Value
. Without re-executing the factory method. So in the end, this is the same problem as the static constructor problem. The Lazy<T>
docs have the following to say:
The Lazy stands in for an actual T that otherwise would have been initialized at some earlier point, usually during startup. A failure at that earlier point is usually fatal. If there is a potential for a recoverable failure, we recommend that you build the retry logic into the initialization routine (in this case, the factory method), just as you would if you weren't using lazy initialization.
MSDN docs
So if you really must throw exceptions in your constructor, be sure to handle them in the factory method.
Exceptions and thread-safety
There's one more workaround for the problem of exceptions in constructors. Lazy
has three thread-safety modes, defined in the enum System.Threading.LazyThreadSafetyMode
which can be passed to the constructor of Lazy<T>
.
None
. No thread safety.
ExecutionAndPublication
. This is the default. This ensures that the factory method is executed only once, and that the object onlazy.Value
is always the same across threads.
PublicationOnly
. This only ensures thread-safety onlazy.Value
. It can happen that the factory method is executed simultaneously by multiple threads, but the resulting instance is still the same. The others are discarded. According to theLazy<T>
docs, Exceptions are not cached here.
This leaves you, the implementer of the singleton with a decision: if there are exceptions that might be thrown, that can't be handled within the factory method, and that might not throw in subsequent attempts (weird, but might happen), you could consider loosening up some of the locking on Lazy
to allow for this behaviour.
For further reading, see this blog post by Jon Skeet.
$endgroup$
Your implementation does the trick. For what it's worth, I would consider your implementation the current "traditional way". It is thread-safe. The static constructor is guaranteed to run only once, so you won't accidentally end up with two instances if two threads try to grab the instance for the first time simultaneously.
Laziness
There is one more thing you might want to consider though. Because of the way the static constructor works, it is executed the first time the class is referenced in the code. This means that the instance in your singleton is created, even when you don't try to grab the instance, but another static variable perhaps.
To fix this, you might want to make the creation of the instance lazy, so that it really only fires when you need it. To do this, you can use the Lazy<T>
class.
Sealed
This is mostly a formality, but it's nice when trying to do it formally. The sealed
keyword means that that class cannot be inherited from. The private constructor already ensured that, but this makes it more explicit.
Readonly
As Jesse mentioned in the comments, it's a good idea to make the instance field (lazy or not) readonly
. This prevents you from accidentally mucking up your singleton instance from within the class.
public sealed class Person
{
private Person() { }
private static readonly Lazy<Person> lazyPersonInstance = new Lazy<Person>(() => new Person());
public static Person GetPersonInstance()
{
return lazyPersonInstance.Value;
}
}
Your method GetPersonInstance
can also be a getter-property:
public static Person Instance => lazyPersonInstance.Value;
Exceptions
IEatBagels already posted an answer about throwing exceptions. I'll elaborate a bit on how it would work in this example. We're looking at the scenario where instantiating the singleton instance throws an exception.
In your code, this exception would be thrown when the static constructor is ran. As IEatBagels points out, when this happens, the type is broken for the rest of the "program". This means that you have one shot at creating your instance.
In my example, the initiation of the instance does not happen during the execution of the static constructor. All we do during static initialization - static constructor and static fields act similarly IIRC - is creating the Lazy<T>
object with the factory method. This method is only executed when lazyPersonInstance.Value
is called.
However, Lazy<T>
caches exceptions. This means that if the factory method throws an exception, that exception will be rethrown on every subsequent call to lazyPersonInstance.Value
. Without re-executing the factory method. So in the end, this is the same problem as the static constructor problem. The Lazy<T>
docs have the following to say:
The Lazy stands in for an actual T that otherwise would have been initialized at some earlier point, usually during startup. A failure at that earlier point is usually fatal. If there is a potential for a recoverable failure, we recommend that you build the retry logic into the initialization routine (in this case, the factory method), just as you would if you weren't using lazy initialization.
MSDN docs
So if you really must throw exceptions in your constructor, be sure to handle them in the factory method.
Exceptions and thread-safety
There's one more workaround for the problem of exceptions in constructors. Lazy
has three thread-safety modes, defined in the enum System.Threading.LazyThreadSafetyMode
which can be passed to the constructor of Lazy<T>
.
None
. No thread safety.
ExecutionAndPublication
. This is the default. This ensures that the factory method is executed only once, and that the object onlazy.Value
is always the same across threads.
PublicationOnly
. This only ensures thread-safety onlazy.Value
. It can happen that the factory method is executed simultaneously by multiple threads, but the resulting instance is still the same. The others are discarded. According to theLazy<T>
docs, Exceptions are not cached here.
This leaves you, the implementer of the singleton with a decision: if there are exceptions that might be thrown, that can't be handled within the factory method, and that might not throw in subsequent attempts (weird, but might happen), you could consider loosening up some of the locking on Lazy
to allow for this behaviour.
For further reading, see this blog post by Jon Skeet.
edited 23 hours ago
answered yesterday
JADJAD
1,1251 gold badge6 silver badges23 bronze badges
1,1251 gold badge6 silver badges23 bronze badges
4
$begingroup$
One small note - to truly be a singleton, the class should also besealed
so no inheritors can be created and change behavior.
$endgroup$
– Jesse C. Slicer
yesterday
4
$begingroup$
@jessecslicer hmm, I was going to mention that, but the private constructor already prevents inheritance. It's never a bad idea though.
$endgroup$
– JAD
yesterday
5
$begingroup$
I'd probably also marklazyPersonInstance
asreadonly
to keep other methods from being able to muck around with it, even by accident.
$endgroup$
– Jesse C. Slicer
yesterday
1
$begingroup$
@JesseC.Slicer thanks, added :)
$endgroup$
– JAD
yesterday
add a comment |
4
$begingroup$
One small note - to truly be a singleton, the class should also besealed
so no inheritors can be created and change behavior.
$endgroup$
– Jesse C. Slicer
yesterday
4
$begingroup$
@jessecslicer hmm, I was going to mention that, but the private constructor already prevents inheritance. It's never a bad idea though.
$endgroup$
– JAD
yesterday
5
$begingroup$
I'd probably also marklazyPersonInstance
asreadonly
to keep other methods from being able to muck around with it, even by accident.
$endgroup$
– Jesse C. Slicer
yesterday
1
$begingroup$
@JesseC.Slicer thanks, added :)
$endgroup$
– JAD
yesterday
4
4
$begingroup$
One small note - to truly be a singleton, the class should also be
sealed
so no inheritors can be created and change behavior.$endgroup$
– Jesse C. Slicer
yesterday
$begingroup$
One small note - to truly be a singleton, the class should also be
sealed
so no inheritors can be created and change behavior.$endgroup$
– Jesse C. Slicer
yesterday
4
4
$begingroup$
@jessecslicer hmm, I was going to mention that, but the private constructor already prevents inheritance. It's never a bad idea though.
$endgroup$
– JAD
yesterday
$begingroup$
@jessecslicer hmm, I was going to mention that, but the private constructor already prevents inheritance. It's never a bad idea though.
$endgroup$
– JAD
yesterday
5
5
$begingroup$
I'd probably also mark
lazyPersonInstance
as readonly
to keep other methods from being able to muck around with it, even by accident.$endgroup$
– Jesse C. Slicer
yesterday
$begingroup$
I'd probably also mark
lazyPersonInstance
as readonly
to keep other methods from being able to muck around with it, even by accident.$endgroup$
– Jesse C. Slicer
yesterday
1
1
$begingroup$
@JesseC.Slicer thanks, added :)
$endgroup$
– JAD
yesterday
$begingroup$
@JesseC.Slicer thanks, added :)
$endgroup$
– JAD
yesterday
add a comment |
$begingroup$
There's a potential bug with this scenario.
According to this Jon Skeet post, if an exception is thrown inside the static
constructor, it is never retried. Which means that if your Singleton initialization has a problem, your Singleton is doomed for the lifetime of your application, which normally isn't a problem with the "traditional" way of doing it.
$endgroup$
$begingroup$
good catch. real world (constructors) vs academic examples.
$endgroup$
– granadaCoder
16 hours ago
add a comment |
$begingroup$
There's a potential bug with this scenario.
According to this Jon Skeet post, if an exception is thrown inside the static
constructor, it is never retried. Which means that if your Singleton initialization has a problem, your Singleton is doomed for the lifetime of your application, which normally isn't a problem with the "traditional" way of doing it.
$endgroup$
$begingroup$
good catch. real world (constructors) vs academic examples.
$endgroup$
– granadaCoder
16 hours ago
add a comment |
$begingroup$
There's a potential bug with this scenario.
According to this Jon Skeet post, if an exception is thrown inside the static
constructor, it is never retried. Which means that if your Singleton initialization has a problem, your Singleton is doomed for the lifetime of your application, which normally isn't a problem with the "traditional" way of doing it.
$endgroup$
There's a potential bug with this scenario.
According to this Jon Skeet post, if an exception is thrown inside the static
constructor, it is never retried. Which means that if your Singleton initialization has a problem, your Singleton is doomed for the lifetime of your application, which normally isn't a problem with the "traditional" way of doing it.
answered yesterday
IEatBagelsIEatBagels
9,9502 gold badges35 silver badges86 bronze badges
9,9502 gold badges35 silver badges86 bronze badges
$begingroup$
good catch. real world (constructors) vs academic examples.
$endgroup$
– granadaCoder
16 hours ago
add a comment |
$begingroup$
good catch. real world (constructors) vs academic examples.
$endgroup$
– granadaCoder
16 hours ago
$begingroup$
good catch. real world (constructors) vs academic examples.
$endgroup$
– granadaCoder
16 hours ago
$begingroup$
good catch. real world (constructors) vs academic examples.
$endgroup$
– granadaCoder
16 hours ago
add a comment |
pejman is a new contributor. Be nice, and check out our Code of Conduct.
pejman is a new contributor. Be nice, and check out our Code of Conduct.
pejman is a new contributor. Be nice, and check out our Code of Conduct.
pejman is a new contributor. Be nice, and check out our Code of Conduct.
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f226611%2fsingleton-design-pattern-implementation-in-a-not-traditional-way%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
3
$begingroup$
csharpindepth.com/articles/singleton. Jon Skeet article on singleton. It's some kind of cannonical read before starting any conversation about singleton.
$endgroup$
– xdtTransform
23 hours ago
$begingroup$
I can't deal with the capitalization of
SingleTonSample
in the article OP posted.$endgroup$
– JPhi1618
15 hours ago