Singleton service class with inheritance
$begingroup$
There is a service class (ProposalPdfService
) in one of our assemblies that has implementation logic specific to that app's assembly. Previously (and, I believe, erroneously) I treated it as a quasi-singleton by making it and all its members static, but I refactored it to use the singleton pattern described here using the Lazy<T>
type.
Upon needing to share a generic subset of this service's functionality with another assembly, I decided to move that functionality into a base class (PdfServiceBase
) in a shared assembly used by both apps.
This second app can use the base service as-is — there are currently no plans to add any implementation-specific logic for this app — while the main app uses ProposalPdfService
, which inherits from PdfServiceBase
. Both classes are singletons.
public class PdfServiceBase
{
private static readonly Lazy<PdfServiceBase> lazy = new Lazy<PdfServiceBase>(() => new PdfServiceBase());
public static PdfServiceBase Instance { get => lazy.Value; }
protected PdfServiceBase() { }
public PdfDocument RetrievePdfFile(string relativeFilePath, string relativeFileName)
{
PdfDocument pdf = null;
string directoryWithoutLastBackSlash = FilePathManager.GetDocumentsFilePath("PDFs");
string filePath = directoryWithoutLastBackSlash + @"" + relativeFilePath;
string fileName = filePath + @"" + relativeFileName + ".pdf";
// Check if file exists
if (System.IO.File.Exists(fileName))
pdf = PdfDocument.FromFile(fileName);
return pdf;
}
}
public sealed class ProposalPdfService : PdfServiceBase
{
private static readonly Lazy<ProposalPdfService> lazy = new Lazy<ProposalPdfService>(() => new ProposalPdfService());
public static new ProposalPdfService Instance { get => lazy.Value; }
private ProposalPdfService() { }
// app-specific service members listed below...
public string Foo { get; } = "foo";
}
I specifically chose inheritance over containment because, in my opinion, it would be very clumsy to have to remember to use the base class service just to use the RetrievePdfFile
method. Containment would also require having an instance of ProposalPdfService
and PdfServiceBase
. Being able to invoke ProposalPdfService.RetrievePdfFile
makes good sense to me.
The only thing that feels "weird" about this implementation to me is that, due to both classes being able to be instantiated as independent singletons, they both have Instance
members, meaning that the derived property has to shadow the base property using the new
keyword. And I know shadowing is one of those things people typically associate with poor design.
I'm generally happy with this implementation, but as this is my first time implementing a "real" singleton and, due to the inheritance, it's not so straight forward, I wanted to get some feedback on it. Do you see any problems with this approach? Or, if it's the right approach, are there any improvements I could make?
c# inheritance singleton
New contributor
$endgroup$
add a comment |
$begingroup$
There is a service class (ProposalPdfService
) in one of our assemblies that has implementation logic specific to that app's assembly. Previously (and, I believe, erroneously) I treated it as a quasi-singleton by making it and all its members static, but I refactored it to use the singleton pattern described here using the Lazy<T>
type.
Upon needing to share a generic subset of this service's functionality with another assembly, I decided to move that functionality into a base class (PdfServiceBase
) in a shared assembly used by both apps.
This second app can use the base service as-is — there are currently no plans to add any implementation-specific logic for this app — while the main app uses ProposalPdfService
, which inherits from PdfServiceBase
. Both classes are singletons.
public class PdfServiceBase
{
private static readonly Lazy<PdfServiceBase> lazy = new Lazy<PdfServiceBase>(() => new PdfServiceBase());
public static PdfServiceBase Instance { get => lazy.Value; }
protected PdfServiceBase() { }
public PdfDocument RetrievePdfFile(string relativeFilePath, string relativeFileName)
{
PdfDocument pdf = null;
string directoryWithoutLastBackSlash = FilePathManager.GetDocumentsFilePath("PDFs");
string filePath = directoryWithoutLastBackSlash + @"" + relativeFilePath;
string fileName = filePath + @"" + relativeFileName + ".pdf";
// Check if file exists
if (System.IO.File.Exists(fileName))
pdf = PdfDocument.FromFile(fileName);
return pdf;
}
}
public sealed class ProposalPdfService : PdfServiceBase
{
private static readonly Lazy<ProposalPdfService> lazy = new Lazy<ProposalPdfService>(() => new ProposalPdfService());
public static new ProposalPdfService Instance { get => lazy.Value; }
private ProposalPdfService() { }
// app-specific service members listed below...
public string Foo { get; } = "foo";
}
I specifically chose inheritance over containment because, in my opinion, it would be very clumsy to have to remember to use the base class service just to use the RetrievePdfFile
method. Containment would also require having an instance of ProposalPdfService
and PdfServiceBase
. Being able to invoke ProposalPdfService.RetrievePdfFile
makes good sense to me.
The only thing that feels "weird" about this implementation to me is that, due to both classes being able to be instantiated as independent singletons, they both have Instance
members, meaning that the derived property has to shadow the base property using the new
keyword. And I know shadowing is one of those things people typically associate with poor design.
I'm generally happy with this implementation, but as this is my first time implementing a "real" singleton and, due to the inheritance, it's not so straight forward, I wanted to get some feedback on it. Do you see any problems with this approach? Or, if it's the right approach, are there any improvements I could make?
c# inheritance singleton
New contributor
$endgroup$
add a comment |
$begingroup$
There is a service class (ProposalPdfService
) in one of our assemblies that has implementation logic specific to that app's assembly. Previously (and, I believe, erroneously) I treated it as a quasi-singleton by making it and all its members static, but I refactored it to use the singleton pattern described here using the Lazy<T>
type.
Upon needing to share a generic subset of this service's functionality with another assembly, I decided to move that functionality into a base class (PdfServiceBase
) in a shared assembly used by both apps.
This second app can use the base service as-is — there are currently no plans to add any implementation-specific logic for this app — while the main app uses ProposalPdfService
, which inherits from PdfServiceBase
. Both classes are singletons.
public class PdfServiceBase
{
private static readonly Lazy<PdfServiceBase> lazy = new Lazy<PdfServiceBase>(() => new PdfServiceBase());
public static PdfServiceBase Instance { get => lazy.Value; }
protected PdfServiceBase() { }
public PdfDocument RetrievePdfFile(string relativeFilePath, string relativeFileName)
{
PdfDocument pdf = null;
string directoryWithoutLastBackSlash = FilePathManager.GetDocumentsFilePath("PDFs");
string filePath = directoryWithoutLastBackSlash + @"" + relativeFilePath;
string fileName = filePath + @"" + relativeFileName + ".pdf";
// Check if file exists
if (System.IO.File.Exists(fileName))
pdf = PdfDocument.FromFile(fileName);
return pdf;
}
}
public sealed class ProposalPdfService : PdfServiceBase
{
private static readonly Lazy<ProposalPdfService> lazy = new Lazy<ProposalPdfService>(() => new ProposalPdfService());
public static new ProposalPdfService Instance { get => lazy.Value; }
private ProposalPdfService() { }
// app-specific service members listed below...
public string Foo { get; } = "foo";
}
I specifically chose inheritance over containment because, in my opinion, it would be very clumsy to have to remember to use the base class service just to use the RetrievePdfFile
method. Containment would also require having an instance of ProposalPdfService
and PdfServiceBase
. Being able to invoke ProposalPdfService.RetrievePdfFile
makes good sense to me.
The only thing that feels "weird" about this implementation to me is that, due to both classes being able to be instantiated as independent singletons, they both have Instance
members, meaning that the derived property has to shadow the base property using the new
keyword. And I know shadowing is one of those things people typically associate with poor design.
I'm generally happy with this implementation, but as this is my first time implementing a "real" singleton and, due to the inheritance, it's not so straight forward, I wanted to get some feedback on it. Do you see any problems with this approach? Or, if it's the right approach, are there any improvements I could make?
c# inheritance singleton
New contributor
$endgroup$
There is a service class (ProposalPdfService
) in one of our assemblies that has implementation logic specific to that app's assembly. Previously (and, I believe, erroneously) I treated it as a quasi-singleton by making it and all its members static, but I refactored it to use the singleton pattern described here using the Lazy<T>
type.
Upon needing to share a generic subset of this service's functionality with another assembly, I decided to move that functionality into a base class (PdfServiceBase
) in a shared assembly used by both apps.
This second app can use the base service as-is — there are currently no plans to add any implementation-specific logic for this app — while the main app uses ProposalPdfService
, which inherits from PdfServiceBase
. Both classes are singletons.
public class PdfServiceBase
{
private static readonly Lazy<PdfServiceBase> lazy = new Lazy<PdfServiceBase>(() => new PdfServiceBase());
public static PdfServiceBase Instance { get => lazy.Value; }
protected PdfServiceBase() { }
public PdfDocument RetrievePdfFile(string relativeFilePath, string relativeFileName)
{
PdfDocument pdf = null;
string directoryWithoutLastBackSlash = FilePathManager.GetDocumentsFilePath("PDFs");
string filePath = directoryWithoutLastBackSlash + @"" + relativeFilePath;
string fileName = filePath + @"" + relativeFileName + ".pdf";
// Check if file exists
if (System.IO.File.Exists(fileName))
pdf = PdfDocument.FromFile(fileName);
return pdf;
}
}
public sealed class ProposalPdfService : PdfServiceBase
{
private static readonly Lazy<ProposalPdfService> lazy = new Lazy<ProposalPdfService>(() => new ProposalPdfService());
public static new ProposalPdfService Instance { get => lazy.Value; }
private ProposalPdfService() { }
// app-specific service members listed below...
public string Foo { get; } = "foo";
}
I specifically chose inheritance over containment because, in my opinion, it would be very clumsy to have to remember to use the base class service just to use the RetrievePdfFile
method. Containment would also require having an instance of ProposalPdfService
and PdfServiceBase
. Being able to invoke ProposalPdfService.RetrievePdfFile
makes good sense to me.
The only thing that feels "weird" about this implementation to me is that, due to both classes being able to be instantiated as independent singletons, they both have Instance
members, meaning that the derived property has to shadow the base property using the new
keyword. And I know shadowing is one of those things people typically associate with poor design.
I'm generally happy with this implementation, but as this is my first time implementing a "real" singleton and, due to the inheritance, it's not so straight forward, I wanted to get some feedback on it. Do you see any problems with this approach? Or, if it's the right approach, are there any improvements I could make?
c# inheritance singleton
c# inheritance singleton
New contributor
New contributor
edited 4 hours ago
Jacob Stamm
New contributor
asked 4 hours ago
Jacob StammJacob Stamm
1012
1012
New contributor
New contributor
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
$begingroup$
I believe a requirement of a “true” singleton is that it’s supposed to be sealed and can’t be inherited. The very article you linked states as much. This is why things feel a bit off to you, you’re only respecting the pattern for one of the classes.
Consider having PdfServiceBase
be an abstract class that implements RetrievePdfFile()
and any other common code like that, then implement ProposalPdfService
and something like just PdfService
as singletons each implementing the pattern properly and separately, without “new”.
New contributor
$endgroup$
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
});
});
}, "mathjax-editing");
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
});
}
});
Jacob Stamm 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%2f214280%2fsingleton-service-class-with-inheritance%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
$begingroup$
I believe a requirement of a “true” singleton is that it’s supposed to be sealed and can’t be inherited. The very article you linked states as much. This is why things feel a bit off to you, you’re only respecting the pattern for one of the classes.
Consider having PdfServiceBase
be an abstract class that implements RetrievePdfFile()
and any other common code like that, then implement ProposalPdfService
and something like just PdfService
as singletons each implementing the pattern properly and separately, without “new”.
New contributor
$endgroup$
add a comment |
$begingroup$
I believe a requirement of a “true” singleton is that it’s supposed to be sealed and can’t be inherited. The very article you linked states as much. This is why things feel a bit off to you, you’re only respecting the pattern for one of the classes.
Consider having PdfServiceBase
be an abstract class that implements RetrievePdfFile()
and any other common code like that, then implement ProposalPdfService
and something like just PdfService
as singletons each implementing the pattern properly and separately, without “new”.
New contributor
$endgroup$
add a comment |
$begingroup$
I believe a requirement of a “true” singleton is that it’s supposed to be sealed and can’t be inherited. The very article you linked states as much. This is why things feel a bit off to you, you’re only respecting the pattern for one of the classes.
Consider having PdfServiceBase
be an abstract class that implements RetrievePdfFile()
and any other common code like that, then implement ProposalPdfService
and something like just PdfService
as singletons each implementing the pattern properly and separately, without “new”.
New contributor
$endgroup$
I believe a requirement of a “true” singleton is that it’s supposed to be sealed and can’t be inherited. The very article you linked states as much. This is why things feel a bit off to you, you’re only respecting the pattern for one of the classes.
Consider having PdfServiceBase
be an abstract class that implements RetrievePdfFile()
and any other common code like that, then implement ProposalPdfService
and something like just PdfService
as singletons each implementing the pattern properly and separately, without “new”.
New contributor
New contributor
answered 1 hour ago
AKDAKD
212
212
New contributor
New contributor
add a comment |
add a comment |
Jacob Stamm is a new contributor. Be nice, and check out our Code of Conduct.
Jacob Stamm is a new contributor. Be nice, and check out our Code of Conduct.
Jacob Stamm is a new contributor. Be nice, and check out our Code of Conduct.
Jacob Stamm 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%2f214280%2fsingleton-service-class-with-inheritance%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