views:

102

answers:

3

I'd like some advice on building in known errors. Let's say I have a Windows form that needs to set the source path of an image in an object. It must be:

  • A valid path
  • An image
  • A PNG
  • 32 x 32 in size
  • No transparency

The thing about catching errors is that I'd like the class to handle the errors as much as possible, instead of the Windows form.

So let's say I had:

Public Class MyImage
    Public Property SourcePath As String
End Class

and

Sub TestImage()
    Dim imgPath As New MyImage
    Try
        imgPath.SourcePath = "C:\My Documents\image001.png".
    Catch ex As Exception
 MsgBox(ex)
    End Try
End Sub

SourcePath should be a string path that points to a valid image file, that is a png, that is 32x32 and has no transparency. If it is not one or more of those, I just want the ex to report back what error(s) are there (like "The image is not 32x32" or "The image contains transparency, which is should not. And it also is not 32x32.). How can I create my own Exceptions for the property SourcePath above?

On top of this, let's say I had all the same requirements above, but instead of a 32x32 size, I required a 48x48 size for the image on the SourcePath. Is there a way to customize for this?

Thx in advance

+5  A: 

use something like this:

public class InvalidImageException : Exception
{
    public InvalidImageException() { }
    public InvalidImageException(string message)
        : base(message) { }
    public InvalidImageException(string message, Exception innerException)
        : base(message, innerException) { }
    public InvalidImageException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
        : base(info, context) { }
    public InvalidImageException(string message, MyImage image)
        : base(message) 
    {
        this.Image = image;
    }
    public MyImage Image { get; set; }
}

You should probably not be throwing exceptions while setting the SourcePath property. Possibly either have that logic in the constructor (accept a string, sourcepath into the constructor and throw validations). Either way, the code would look something like this...

public class MyImage
{
    public MyImage(string sourcePath)
    {
        this.SourcePath = sourcePath;
        //This is where you could possibly do the tests. some examples of how you would do them are given below
        //You could move these validations into the SourcePath property, it all depends on the usage of the class
        if(this.height != 32)
            throw new InvalidImageException("Height is not valid" this);
        if(this.Width != 32)
            throw new InvalidImageException("Width is not valid",this);
        //etc etc
    }
    public string SourcePath { get; private set; }
}

Then your code would look like this...

try
{
    imgPath = new MyImage("C:\My Documents\image001.png");
}
catch(InvalidImageException invalidImage)
{
    MsgBox.Show(invalidImage.Message);
}
catch(Exception ex)
{
    //Handle true failures such as file not found, permission denied, invalid format etc
}
TerrorAustralis
+1 -- but you should implement the four constructors of Exception.
Billy ONeal
Ordinarily i would completely agree Billy, but as the four constructors relate to the setting of the message i was not sure if they should be permitted in the derived class. Maybe this should be a fifth constructor?
TerrorAustralis
Yeah, something like this. A couple of questions: 1) what is the `invalidImage` that you've used in the `Catch`? 2) in the `Sub New(image as MyImage)` you've used above for the `InvalidImageException` what should I be doing to create the exceptions? Just a bunch of if/thens and then building a string of possible errors?
WinnerWinnerChickenDinner
I don't agree with performing the checks inside the Exception constructor - how do you know that you need to create an exception unless you have already performed those checks?
Kragen
Kragen, neither do i, my edited post reflects that. But the OP looked like he was trying to throw exceptions on the setting of a property, which were not in any way related to the property so i went for a basic answer. The current edits take into account more standard coding practices
TerrorAustralis
Excellent, thank you!
WinnerWinnerChickenDinner
+2  A: 

In the setter for the SourcePath property you want to do your validity checking, and throw exceptions as needed.

You can either throw a built-in exception type and pass a string to it to give a specific error, or you can create your own exception classes derived from System.Exception.

Andrew Cooper
I like the idea of using the setter for validation in my property, unfortunately I can't find a way to kick back a validation error to the WinForm from the class.
WinnerWinnerChickenDinner
An example would be (in your property setter) `throw new exception("Size is not valid");` That would get sent to the Catch Ex statement and the message would be "Size is not valid"
TerrorAustralis
+2  A: 

There are many ways that you might choose to do this, however I'd probably do something along the lines of:

void TestImage()
{
    MyImage image = new MyImage();
    try
    {
        image.Load("@C:\My Documents\image001.png");
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

Where image.Load() looks a little bit like:

void Load(string path)
{
    if (!File.Exists(path))
    {
        throw new FileNotFoundException("File '" + path + "' does not exist.");
    }
    if (/* image is wrong size */)
    {
        throw new InvalidImageSizeException("File " + path + " is not in the correct size - expected 32x32 pixels");
    }
    // etc...
}

Some people would argue that you should have your own custom exception type - you can if you like but I've only bothered when the standard exception types don't really cover the exception circumstance (for example InvalidImageSizeException).

Kragen
Thanks for this, it is another good way of looking at it.
WinnerWinnerChickenDinner