What to do on null object in C#

Started by
6 comments, last by deadstar 15 years, 3 months ago
Hello, I've got a few side projects going and ran into a bit of a coding nightmare. I've come up with a solution, but I really don't like it and was hoping that there is a graceful way to do this in C# without resorting to what I think is a very naive solution. I'm using OpenAL to load and play a sound file, but the code needs to deal with sound objects that might have failed at loading. An example would be as follows:
Sound mySound = SoundHandler.Instance.GetSound("audio.wav");
mySound.Position = new Vector3(100, 0, 0);
mySound.Play();
It's possible that SoundHandler may return a null object if the file audio.wav does not exist, or some other error occurred. Which, of course, would result in a NullReferenceException. Each sound object has a IsLoaded property, which is true if the Sound object loaded properly. So what I did was I programmed SoundHandler to return a Sound object with the IsLoaded property set to false. Then I've added one line of code to the start of every Sound method. example:
        /// <summary>
        /// Plays the sound source.
        /// </summary>
        public void Play()
        {
            if (!IsLoaded) return;
            Al.alSourcePlay(s_source[0]);
        }

        /// <summary>
        /// Stops the sound source.
        /// </summary>
        public void Stop()
        {
            if (!IsLoaded) return;
            Al.alSourceStop(s_source[0]);
        }

        /// <summary>
        /// Pauses the sound source.
        /// </summary>
        public void Pause()
        {
            if (!IsLoaded) return;
            Al.alSourcePause(s_source[0]);
        }



Is there a neater way to do this? I was thinking about using delegates with the names Play, Pause, Stop, etc and then pointing them at an empty method in the Sound constructor if the audio fails to load... but I'm not sure if that's the best way. Suggestions? Thanks, Giawa
Advertisement
You could test if the returned object is null, surely?

Sound mySound = SoundHandler.Instance.GetSound("audio.wav");if(mySound == null){  //Do something}


...or am I trying the "too obvious" approach and missed something here?

"The right, man, in the wrong, place, can make all the dif-fer-rence in the world..." - GMan, Half-Life 2

A blog of my SEGA Megadrive development adventures: http://www.bigevilcorporation.co.uk

You're right, I can do that. But I want an elegant way of dealing with missing files and such that doesn't require a test for null. I'd also prefer to not have to use a try {} catch {} statement.

I'm thinking an interface might be the best way to approach this? and then return either an object with empty methods or an object with working methods.

Edit: Also, this may not load and play the sound file in the same place in code. So there might be several places that can call methods for the same Sound object, which would result in a lot of

if (mySound != null){     // do something} 
Whatever; that works well enough. File.Exists iirc also might help. A factory might be more architecturally pleasing. Send in 'hey, load file at X' and it gives you the file or some sane default if it's not there.

Practically speaking though, that tends to be a bit more work if all you need is no explosions if the file is missing...
Quote:Original post by Giawa
You're right, I can do that. But I want an elegant way of dealing with missing files and such that doesn't require a test for null. I'd also prefer to not have to use a try {} catch {} statement.

I'm thinking an interface might be the best way to approach this? and then return either an object with empty methods or an object with working methods.

Edit: Also, this may not load and play the sound file in the same place in code. So there might be several places that can call methods for the same Sound object, which would result in a lot of

*** Source Snippet Removed ***


Ah I understand the problem now, you want the object to 'behave as normal' even if it couldn't retrieve any data from file.

Well, the way you're already doing it looks fine to me, and Telastyn's idea of returning a default sounds neat but could be simplified a little: what if the object's constructor* set up some default data? You wouldn't need a factory then, and that default data would be untouched if the file failed to load.


*EDIT: Just realised it's C#, no constructor necessary to initialise a variable *slaps forehead*

"The right, man, in the wrong, place, can make all the dif-fer-rence in the world..." - GMan, Half-Life 2

A blog of my SEGA Megadrive development adventures: http://www.bigevilcorporation.co.uk

Red herring default resources that are ugly and noticeable along with scary error messages saved to log files are a good way to run through your game and catch missing or broken assets without having to deal with each one right away as they crash your program or throw an exception. That way you can assume that every resource you get will at least be valid, if not correct, and don't have to check it everywhere. And if those default resources fail to load, then that would be a good time for a crash or exception because it means something is seriously wrong.
I'd design the system like this:

// Loads and returns the sound inside file 'filename'. //// The loading part may be skipped in some cases// (for instance, if the function was recently called// with the same argument).//// If the file could not be found or opened, it throws// SoundFileReadException.//// If the file could be found and opened, but the format// was invalid, it throws SoundFileFormatException.//// If the file was found and opened and is valid, but // an internal error happened, throws SoundLoadException.Sound GetSound(string filename) {...}


In my opinion, the only responsibility of an elementary "GetSound" function should be to load a sound from a file (perhaps with performance improvements). The code that uses the function is then responsible for reacting to possible errors in an appropriate manner (a single-player game should load a default, a multi-player game should ask the server for the file, then load a default). This also has the benefit of allowing you to count easily how many loading failures were encountered (so that you can react differently if 1% of your assets or 99% of your assets are missing).
Quote:Original post by Zipster
Red herring default resources that are ugly and noticeable


Source Engine's giant flashing red "ERROR" default 3D model was always useful. I might do something like this myself.

"The right, man, in the wrong, place, can make all the dif-fer-rence in the world..." - GMan, Half-Life 2

A blog of my SEGA Megadrive development adventures: http://www.bigevilcorporation.co.uk

This topic is closed to new replies.

Advertisement