Singleton designs and exceptions

K

KC

Greeting all!

I have a problem that I'm hoping will be of interest to others here, and
maybe a solution will crop up. I appoligize for the message's length.

Now, I'm new to C# and .NET, so I am developing an application during my
learning phase. Because of this, I'm trying to use as many *features* as is
reasonable. Some may be more reasonable than others :) Keep that in mind.

OK, basicaly my problem is how to handle exceptions in constructors for
Singletons. Let me set it up:

I have (among others of course) a MainForm class, a Profiles class and a
ProfilesXmlFile class. The purpose of the MainForm class is obvious, the
Profiles class keeps a list of Profile class instances and the
ProfilesXmlFile class reads and writes the list of Profile instances to
an...erm..XML file. A Profile is simply a set of parameters under which the
application works. The user can only select one Profile at any time.

So, I only want/need one instance of the Profiles class, and only one
instance of the ProfilesXmlFile. I can choose many different ways to
approach this, of course, but for the sake of the learning experience I
chose Singletons. I follow MS's recommended approach:

sealed class Profiles {
private ArrayList theProfiles;
public static readonly Profiles Instance = new Profiles();
private Profiles() {
ProfilesXmlFile xmlFile = ProfilesXmlFile.Instance;
theProfiles = xmlFile.LoadProfiles();
}
}

sealed class ProfilesXmlFile {
private XmlDocument doc;
public static readonly ProfilesXmlFile Instance = new ProfilesXmlFile();
private ProfilesXmlFile() {
doc = new XmlDocument();
doc.Load("profiles.xml");
}
public ArrayList LoadProfile() {...}
}

During application initialization, I do this in MainForm:
Profiles myProfiles = Profiles.Instance;

Like I said before, Singletons are not necessary, but it helps me explore
the language.

The problem lies in the exception handling. "doc.Load("profiles.xml")" in
the ProfilesXmlFile class's contructor can throw a couple of exceptions
(FileNotFoundException and XmlException). I want to let the user know that
there was a problem with loading his saved profiles, but ProfilesXmlFile is
not the right place to do that (it is a helper class and should not display
dialog boxes, IMO). Therefore I want to catch the exception and rethrow it
so that Profiles handles it (or prolly even rethrow it there to let MainForm
handle it).

The behaviour is strange though. If I catch FileNotFoundException and
rethrow it (or a custom exception), then I get an "Unhandled exception
FileNotFoundException" raised in that same constructor! The calling class
gets a "TypeInitializationException" (or something like that). I tried for
hours to get some sort of notification to the calling classes that something
went wrong, but the only way to avoid getting "unhandled exception xxx" was
to catch and ignore the exception in the constructor.

How DO you handle exceptions in constructors, and especially for singletons
like the ones I descripbed?

I realize that there are a number of redesigns that will solve the problem.
For instance, I can empty the constructor and do all the work in
LoadProfiles(), which can throw the exceptions. Or I could continue to catch
and set a success/failure flag, and have the calling class do a check to see
if init was successfull. As the class is today, the constructor ignores all
exceptions, but LoadPofiles() checks the status of the doc object (!= null,
HasChildren, etc.).

Anyway, I am probably way out there in la-la land, but let's see what you
think :)
 
J

Jon Skeet [C# MVP]

How DO you handle exceptions in constructors, and especially for singletons
like the ones I descripbed?

What you could do is change Instance to a property like this:

sealed class Profiles
{
static Profiles instance;
static object padlock;

...Constructor as before...

public static Profiles Instance
{
// Thread-safety...
lock (padlock)
{
if (instance==null)
{
// Exception may get thrown here
instance = new Profiles();
}
return instance;
}
}
}
 
K

KC

Thanks for the response.

I see how that could solve it, but that code is not utilizing C#'s built-in
singleton functionality. In that code I have the overhead of locking on
each invokation. That can be fixed with double-checks, i.e.:
if (instance==null)
{
lock (padlock)
{
if (instance==null)
{
// Exception may get thrown here
instance = new Profiles();
}
return instance;
}
}

So, maybe the question should be rephased:
How DO you handle exceptions in constructors, and especially for singletons
like the ones I described, without breaking the MS recommended design (that
uses the built-in functionality).

Thanks again!
 
J

Jon Skeet [C# MVP]

KC said:
Thanks for the response.

I see how that could solve it, but that code is not utilizing C#'s built-in
singleton functionality. In that code I have the overhead of locking on
each invokation. That can be fixed with double-checks, i.e.:
if (instance==null)
{
lock (padlock)
{
if (instance==null)
{
// Exception may get thrown here
instance = new Profiles();
}
return instance;
}
}

No, that *can't* be solved with double-checks, unless instance is
volatile.

See http://www.pobox.com/~skeet/csharp/singleton.html
So, maybe the question should be rephased:
How DO you handle exceptions in constructors, and especially for singletons
like the ones I described, without breaking the MS recommended design (that
uses the built-in functionality).

You could use a static constructor and stash not just the instance but
the exception as well, and make the property:

public Profiles Instance
{
get
{
if (constructionException != null)
{
throw constructionException;
}
return instance;
}
}
 
K

KC

Thanks again!

Jon Skeet said:
No, that *can't* be solved with double-checks, unless instance is
volatile.

See http://www.pobox.com/~skeet/csharp/singleton.html

Well, apparently there is some controversy as to whether that is safe or not
:) Let's leave it
at that. No use risking it though, which is why I like the MS design.
You could use a static constructor and stash not just the instance but
the exception as well, and make the property:

public Profiles Instance
{
get
{
if (constructionException != null)
{
throw constructionException;
}
return instance;
}
}

Yeah, I like that. So, I make the instance variable private and force the
use of the property, which throws the exception (if there was one). I will
test that tonight :)

Thanks!!!

/Kris
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top