JAL Computing

C++COMProgramming .NET Mac Palm CPP/CLI Hobbies

 

Home
Up

Chapter 11 "User Defined Structures"

In this chapter you will learn how to create a user defined error structure for use as a return value. Again, this is a very twisted use-case example that could be hazardous to your mental health! Hopefully, this twisted code will also stimulate your interest in error handling idioms.

Structures

You can declare a structure much like a class like this:

struct MyStruct {
}

However a structure is a value type, not a reference type, and has value type semantics. For instance, the assignment operator creates a copy of a value type and a value type cannot be null. 

For instance, if you try this:

MyStruct ms= new MyStruct();
ms= null;

You will get a compile time error message like this:

 Cannot convert null to 'ResultValue.BoolStruct' because it is a value type

As a first approximation, you can look at a structure as a "lightweight class with value semantics". However, unlike a class, you cannot extend a structure, define a destructor or initialize fields at declaration in a structure. You cannot define a no-arg constructor in a structure since the compiler will insist on doing this for you. If you do define a constructor, it is your responsibility to initialize all fields in the structure. 

Since C# supports the sealed key word (which prevents further sub classing of a class), you can look at a structure as a "a lightweight sealed class with value semantics." 

In most cases you will want the added features and reference semantics of a class. The need for a user defined structure is limited. For example, the efficiency of a structure is nullified if you must store a structure in a collection.  If you pass a value type to a collection that expects a reference to an object, the value will be implicitly copied into an object or "boxed" anyway. However, in my attempts to find a better architecture for handling common non exceptional errors, I stumbled upon a solution best implemented with a structure.

Note: In .NET 2.0 generics come to the rescue! You can create a generic collection that does not box a value type as in List<int> myInts= new List<int>();

A Twisted Example

In this chapter, I introduce the use of a user defined error structure as a return type to signal success or failure. I needed something like the built in simple Boolean value type, but with support for error information. The use of a structure allows the wrapping of a source description and error message in a "Boolean" return value. The use of a value type, guarantees that the return value is not null, simplifying coding. 

First, lets look at the various ways to signal success or failure of an operation. 

bulletReturn null
bulletReturn void, but write to an error log
bulletThrow an Exception on error
bulletReturn true or false and set a "lastError" message
bulletReturn an Enumeration of possible values such as {RESULT_SUCCESS, RESULT_FAILURE}

Note: The .Net naming convention is to use Try, Out when writing a method that returns a boolean to indicate success or failure. The TryParse methods return a boolean to indicate success or failure of the method, rather than throw an exception.

The idiom of returning a bool value and setting a lastError message in an instance field is not very object oriented and is not thread safe. Here is a prototype immutable structure aptly named BoolStruct that is object based and potentially thread safe.

	// wraps bool result, message and source as value type
	// two helper properties for bool result: B and Value
	// immutable structure
	public struct BoolStruct
	{
		public readonly bool isSuccess;
		public readonly String message;
		public readonly String source;
		public BoolStruct(bool isSuccess,String message, String source) 
		{
			if (message == null) {message= "";}
			if (source == null) {source= "";}
			this.isSuccess= isSuccess;
			this.message= message;
			this.source= source;
		}
		public bool B // helper
		{ 
			get {return isSuccess;}
		}
		public bool Value 
		{
			get {return isSuccess;}
		}
	}

Here is a twisted sample class that demonstrates the use of BoolStruct as a return value. Note the use of  a hash of "Open Sesame." Even if the source code is compromised, it will be difficult to recreate the password from the hash value.

// test class
class AliBabaCave
{
	// store hash of PW eg. "Open Sesame".GetHashCode();
	private int hash= 961826045;
	public BoolStruct Open(string key) 
	{
		BoolStruct bs;
		if (key.GetHashCode() == hash)
		{
			bs= new BoolStruct(
				true,
				"Message: Success",		
				"Class: AliBabaCave, Method: Open."
				);
		}
		else 
		{
			bs= new BoolStruct(
				false,
				"Message: Invalid Password",		
				"Class: AliBabaCave, Method: Open."
				);
		}
		System.Console.WriteLine(key);
		return bs;
	}
}

The code can then be tested in main() like this:

static void Main(string[] args)
{
	AliBabaCave cave= new AliBabaCave();
	BoolStruct result= cave.Open("Open Sesame");
	if (result.B) 
	{
		System.Console.WriteLine("Opened Cave.");
	}
	else 
	{
		System.Console.WriteLine("Did not open Cave.");
	}
	System.Console.WriteLine(result.source+" "+result.message);
	result= cave.Open("Kazzam");
	if (result.B) 
	{
		System.Console.WriteLine("Opened Cave.");
	}
	else 
	{
		System.Console.WriteLine("Did not open Cave.");
	}
	System.Console.WriteLine(result.source+" "+result.message);
	Console.ReadLine();
}

Exceptional Behavior

Here is a link to a more conventional discussion of error handling.

In this chapter you learned how to create a user defined error structure. Remember, structures have value semantics, not reference semantics. You can think of a structure as a lightweight sealed class with value semantics.

Have fun,
Jeff

All Rights Reserved Jeff Louie 2003, 2004

 
Send mail to [email protected] with questions or comments about this web site. Copyright © 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 © 
Last modified: 08/04/09
Hosted by www.Geocities.ws

1