remarkpk

I've been writing a C# application for my company, the details of which are not relevant to this post (to spare you, thank god!). However, as I have been the only person working on and designing this project, I am beginning to second-guess myself.

Basically, I have a form levele variable that is being accessed from a separate thread (a timer) and, there is nothing I can do to avoid this, which is fine. I have reduced the number of form level variables being used by using functions and method parameters efficiently.

My question: Because I have designed this application, it works the way I envisioned. However, if certain functions are called out of the order from which they are currently called, exceptions might be raised, like 'NullReferenceException' for sure, as well as others.

Is it bad that a given function's success depends on other functions doing the work of initializing and populating these form level variables before the function can use those variables

Ideally, I would like for any function to be called from anywhere in my code (even if it should be or not) and not raise any exceptions due to a form level variable not being initialized.

Help



Re: Windows Forms General Good programming practice and form level variables!

Matthew Watson

You typically cannot completely avoid this kind of thing. You can mitigate against it by initialising things in the constructor so that either a safe default behaviour occurs, or flags are set that can be checked in the affected functions.

Let's use a concrete example. You have a Person class. It has a DateOfBirth property, and a derived Age property that returns the age of the person in days.

What happens if you create a Person and then access Age without first setting DateOfBirth

There are several options:

(1) Do not have a constructor that does not take a "DateOfBirth" parameter. This is not always possible because it means that there can be no default constructor, which has ramifications for XML serialization. But if it *is* possible, it can be the nicest solution.

(2) Initialise the internal DateOfBirth field to some sensible default. Then Age will return some value. This seems to be a very poor solution, that will silently return invalid data!

(3) If Age is called when DateOfBirth has not been set, treat it as a program error by explicitly detecting that condition and throwing an appropriate exception. This is a good solution, IMHO.

(4) Detect the condition and "patch it up" by returning a certain default value such as, in this example, -1 (which is not a valid age in days). This is not a good solution since it requires the calling code to explicitly check the return value for the special default value.

(5) Check the condition, and do a Debug.Assert() for debug builds, but for release builds return a special value. This suffers from the same problem as (4).

(6) Don't put any special code in place, and let .Net generate its own exceptions. This is a poor solution.

I think for the sort of problem that you proposed, option (3) is going to be the best. Make it an explicit program error, if it is indeed an error to call things out of order.







Re: Windows Forms General Good programming practice and form level variables!

remarkpk

Wow, thanks for the great post!

A couple of follow-up questions:

This particular application is one that must run continuously while it completes some task. So, I didn't want a thrown exception to stop the process.

I've minimized the risk of a function being called and having it use an uninitialized variable by using separate counting integer variables in the functions that are initializing my form level variables and arrays, etc. This way, if I do something like this:

ArrayList blah;

int _blahCount = 0;

void Foo()

{

blah = new ArrayList();

for(int i = 0; i < 10; i++)

{

blah.Add(i.ToString());

_blahCount++;

}

}

void What()
{

//use BlahCount instead of _blah.Count

for(int i = 0; i < BlahCount; i++)

{

MessageBox.Show(_blahIdea.ToString());

}

}

void BlahCount

{

get

{

return _blahCount;

}

}

Doing things that way will prevent me from trying to access _blah.Count if it hadn't yet been instantiated, thus resulting in a NullReferenceException.

This just means that I will have extra counting variables, but that's ok, I think. How does this solution sound Any suggestions





Re: Windows Forms General Good programming practice and form level variables!

Matthew Watson

In that particular example, I would initialise _blah in the constructor to an empty collection. Then all your special checks just go away, since _blah will always be initialised.

In the Foo() method, you would first call _blah.Clear() to empty the array (in case it wasn't already empty) and then fill it in.

You can therefore do away with _blahCount, and have no special cases.




Re: Windows Forms General Good programming practice and form level variables!

remarkpk

Excellent!

Now, what about having an actual array, not an ArrayList. You're example will work perfectly for the ArrayList, but what about initializing an array of custom objects so that a NullReferenceException isn't encountered when I try to access it's Length property





Re: Windows Forms General Good programming practice and form level variables!

Matthew Watson

You just initialise an array in the same way.

private MyType[] _myArrayField = new MyType[0];

Of course, you can't then do _myArrayField.Add(...), because Add() isn't a member of ordinary arrays.
You'd have to create an entire new array and assign it to _myArrayField.


[Edit] I'm sure this thread started off in one of the C# forums - why on earth has it been moved to the Windows Forms forums