JAL Computing
|
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. StructuresYou 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 ExampleIn 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.
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 BehaviorHere 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, 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 ©
|