Frantic Keyboard Mashing

Howdy all!

I’ve been away mashing keys and helping my wonderful wife get started with her super-awesome Wedding Stationery business. It’s early days, and there is still plenty to do, but here is some shameless link touting:

Website (landing page): frogandpencil.com
Blog: frogandpencil.net

I’ll try to do my best to keep up blogging in the meantime (on a random array of interests); I’m expecting to probably come across a few worthy topics along the way as I work on the final website.

Until the next time…

C# 6 Language Features Test Drive

As I was perusing the list of Visual Studio Featured Videos I spotted this little nugget and thought I’d share:

Channel 9 C# 6 Features Video

I’ve taken these features for a drive around the block; in addition to noting down some of my first impressions.

The philosophy outlined is one of small, incremental changes with the emphasis on cleaning up code and reducing boilerplate logic, as opposed to grand concepts that will take time to learn and implement. Sounding all fine and dandy to me 🙂

Here’s the round-up of features outlined…

Getter-Only Auto-Properties

Getter-Only Auto-Properties create a read-only backing field (on compilation) which can be assigned via the constructor or to the property directly as follows (which is consistent with how read-only fields function). Prior to this, it did definitely make it slightly more awkward to work with immutable types in relation to Auto-Properties. With this new syntax in play, the need to include things such as a ‘private set’, for these types, on an Auto-Property will be negated.

Assigning via the constructor:

/// <summary>
/// Outlines the definition for
/// a Rectangle object.
/// </summary>
public class Rectangle
{
	#region Getter-Only Auto-Properties

	/// <summary>
	/// Allows access to the 
	/// Rectangles Height.
	/// </summary>
	public int Height { get; }

	/// <summary>
	/// Allows access to the 
	/// Rectangles Width.
	/// </summary>
	public int Width { get; }

	#endregion Getter-Only Auto-Properties

	#region Constructor

	/// <summary>
	/// Constructor that initialises
	/// this Rectangle.
	/// </summary>
	/// <param name="height">The height of the Rectangle to create.</param>
	/// <param name="width">The width of the Rectangle to create.</param>
	public Rectangle(int height, int width)
	{
		Height = height;
		Width = width;
	}

	#endregion Constructor
}

Assigning to the property directly:

/// <summary>
/// Allows access to the 
/// Rectangles Height.
/// </summary>
public int Height { get; } = 5;

/// <summary>
/// Allows access to the 
/// Rectangles Width.
/// </summary>
public int Width { get; } = 10;

It’s also worth stating here that the direct initialisation of properties works exactly the same way for classic Auto-Properties with getters and setters, so you’re all covered there.

The nameof Operator

When there is a requirement to use the name of a variable/parameter, as a string, directly in code the new ’nameof’ keyword allows you to reference something in a way that will be sensitive to any underlying changes to the variable/parameter name. For instance, if the name of the height/width parameters were altered in the constructor signature for our Rectangle object we can use Visual Studio to directly update the references to these variables within the code that throws exceptions. If these were referenced as strings they would not be updated:

#region Constructor

/// <summary>
/// Constructor that initialises
/// this Rectangle. Exceptions use the nameof keyword
/// to prevent issues whereby variable names change.
/// </summary>
/// <param name="height">The height of the Rectangle to create.</param>
/// <param name="width">The width of the Rectangle to create.</param>
public Rectangle(int height, int width)
{
	//Ensure the height value provided falls within the specified limit
	if (height < minimumLengthAllowed || height > maximumLengthAllowed)
	{
		throw new ArgumentOutOfRangeException(nameof(height));
	}

	//Ensure the width value provided falls within the specified limit
	if (width < minimumLengthAllowed || width > maximumLengthAllowed)
	{
		throw new ArgumentOutOfRangeException(nameof(width));
	}

	//If height matches width then we would have a square! Ensure this is pushed back to the caller as an error
	if (height == width)
	{
		throw new ArgumentException("The parameters provided are of the same value (which will make a square!).", nameof(height));
	}

	//Values provided are safe, initialise this object
	Height = height;
	Width = width;
}

#endregion Constructor

Using Static Members

This next example shows the use of the ‘static’ using clause that targets types instead of namespaces. It’s essentially a fast way to bring into scope static members of a type; this means that you no longer need to reference the type at all when using static members. The following example outlines some code for generating a random rectangle then, within the program class, static members of the Rectangle and Console class are used without needing to be fully qualified.

Outline of the functionality being called within the Rectangle type:

#region Private Constants

//The minimum length (as an integer) for any 'side' of a Rectangle
private const int minimumLengthAllowed = 1;

//The maximum length (as an integer) for any 'side' of a Rectangle
private const int maximumLengthAllowed = 20;

#endregion Private Constants

........

#region Public Static Methods

/// <summary>
/// Public method that returns a Rectangle with a
/// random height and width (within set parameters).
/// </summary>
/// <returns>A Rectangle with a random height and width between the allowed values.</returns>
public static Rectangle GetRandomRectangle()
{
	//Create an rng object and generate a random height/width
	Random rng = new Random();

	int height = rng.Next(minimumLengthAllowed, maximumLengthAllowed + 1), width = rng.Next(minimumLengthAllowed, maximumLengthAllowed + 1);

	//Bit of protection here, increment/decrement the height just to prevent the Rectangle from being a Square (if height matches width)
	CleanRectangleValues(ref height, width);

	//Generate the new Rectangle and return it to the caller
	return new Rectangle(height, width);
}

#endregion Public Static Methods

Bringing static members of the Rectangle and Console types directly into scope:

using System;
using CSharpSixTest.Shapes;

//Bring the static members of the Rectangle and Console types directly into scope (meaning they don't need to be fully qualified)
using static CSharpSixTest.Shapes.Rectangle;
using static System.Console;

namespace CSharpSixTest
{
    /// <summary>
    /// Main Program Class.
    /// </summary>
    class Program
    {
        /// <summary>
        /// Main method.
        /// </summary>
        /// <param name="args">Optional input arguments</param>
        static void Main(string[] args)
        {
            //Create a new random Rectangle calling the static Rectangle class GetRandomRectangle method (notice that the type does not to be included here)
            Rectangle newRectangle = GetRandomRectangle();

            //Use static members of System.Console without needed to fully qualify them (with type)
            WriteLine(newRectangle.Height);
            WriteLine(newRectangle.Width);

            ReadKey();
        }
    }
}

As with static members, the idea expressed here works exactly the same with enums. The features video (link above) that demonstrated this does bring up the interesting point that, if overused, this could cause code to be unnecessarily verbose. I’ll agree here; this is certainly something that I will use sparingly and only whereby the purpose of the member being accessed carries enough clarity on its own without the type prefix being required.

String Interpolation and Expression-Bodied Methods/Properties

I really love String.Format but I would certainly say I’ve tripped up once or twice when specifying larger expressions, whereby multiple arguments are being pushed into a resultant string. With String Interpolation syntax, we can now push values directly into a string, in a very terse and easy to understand way:

Before String Interpolation:


#region Rectangle ToString (old school)

/// <summary>
/// Old style ToString() method.
/// </summary>
/// <returns>A string representation for a Rectangle.</returns>
public override string ToString()
{
	return string.Format("Height = {0}; Width = {1};", Height, Width); 
}

#endregion Rectangle ToString (old school)

After String Interpolation (as an Expression-Bodied method now):

/// <summary>
/// Rectangle overriden ToString() method showing an example
/// of an Expression-Bodied method using String Interpolation.
/// </summary>
/// <returns>A string representation for a Rectangle.</returns>
public override string ToString() => $"Height = { Height }; Width = { Width };"; //Values embedded in statement - Very terse and easy to understand (less error prone)

In this previous example I coupled String Interpolation with a method using Expression-Bodied syntax. This utilises the existing lambda syntax so you can shorthand a method definition into a single line (for very simple method bodies that perform a single function or just exposes a single return statement for example).

The Expression-Bodied syntax can be applied to properties (get only). Notice that the get and return keywords are not required, these are just implied.

Old style Computed Property:

#region Old Style Computed Property

/// <summary>
/// Returns a value that represents the 
/// perimeter for this Rectangle.
/// </summary>
public int Perimeter
{
	get
	{
		return (2 * (Height + Width));
	}
}

#endregion Old Style Computed Property

Expression-Bodied Property:

#region Expression-Bodied Computed Property

/// <summary>
/// Returns a value that represents the 
/// perimeter for this Rectangle.
/// </summary>
public int Perimeter => (2 * (Height + Width));

#endregion Expression-Bodied Computed Property

Index Initialisers

In the past Index Initialisers could not be used with Object Initialisers; however, this is now possible (the below example shows how to break down what would have been four lines of code in a method body down to one, simple Expression-Bodied method).

Old method containing code setting up an object with Index Initialisers:

#region Public Methods

/// <summary>
/// Convert this Rectangle to a Json object.
/// </summary>
/// <returns>A Json object based on a particular Rectangle instance.</returns>
public JObject ToJson()
{
	JObject result = new JObject();
	result["height"] = Height;
	result["width"] = Width;

	return result;
}

#endregion Public Methods

Index Initialisers can now be placed inside Object Initialisers:

#region Public Methods

/// <summary>
/// Convert this Rectangle to a Json object.
/// </summary>
/// <returns>A Json object based on a particular Rectangle instance.</returns>
public JObject ToJson()
{
	JObject result = new JObject() {["height"] = Height, ["width"] = Width };

	return result;
}

#endregion Public Methods

Code cut down further into a single line, Expression-Bodied method:

#region Public Methods

/// <summary>
/// Convert this Rectangle to a Json object.
/// </summary>
/// <returns>A Json object based on a particular Rectangle instance.</returns>
public JObject ToJson() => new JObject() {["height"] = Height, ["width"] = Width };

#endregion Public Methods

Null Conditional Operators

A new operator, dubbed the ‘Elvis Operator’, has been introduced to make short work of null checks (i.e. whereby multiple checks for null are required before calling properties on an object, for example). This is something I really like; the following example shows the reduction in code when using Null Conditional Operators (in additional to bringing in the new ‘using static’ clause so we don’t need to fully qualify enum values).

Code prior to any Null Conditional Operators being applied:

/// <summary>
/// Public static helper method to convert Json
/// into a Rectangle.
/// </summary>
/// <param name="json">The Json object to transform into a Rectangle.</param>
/// <returns>A Rectangle object based on Json.</returns>
public static Rectangle FromJson(JObject json)
{
	//Check the transformation can actually be performed
	if (json != null &&
		json["width"] != null &&
		json["width"].Type == JTokenType.Integer &&
		json["height"] != null &&
		json["height"].Type == JTokenType.Integer)
	{
		//Get the height/width from the Json object
		int height = (int)json["height"], width = (int)json["width"];

		//Tidy these values as appropriate
		CleanRectangleValues(ref height, width);
	   
		//Return a new Rectangle as specified by the values in the Json object
		return new Rectangle(height, width);
	}

	return null;
}

........

/// <summary>
/// Private static helper method that increments/decrements
/// the height value provided based on the width (if they match). 
/// Helps prevent making 'Squares'.
/// </summary>
/// <param name="height">A Rectangles prospective height value (passed by ref).</param>
/// <param name="width">A Rectangles prospective width value.</param>
private static void CleanRectangleValues(ref int height, int width)
{
	//If height matches width see if we need to increment or decrement height (so we end up with values that make a valid Rectangle)
	if (height == width)
	{
		if (height != maximumLengthAllowed)
		{
			height++;
		}
		else
		{
			height--;
		}
	}
}

Only perform the .Type check if the json object contains a height/width property:

/// <summary>
/// Public static helper method to convert Json
/// into a Rectangle.
/// </summary>
/// <param name="json">The Json object to transform into a Rectangle.</param>
/// <returns>A Rectangle object based on Json.</returns>
public static Rectangle FromJson(JObject json)
{
	//Check the transformation can actually be performed
	if (json != null &&
		json["width"]?.Type == JTokenType.Integer &&
		json["height"]?.Type == JTokenType.Integer)
	{
		//Get the height/width from the Json object
		int height = (int)json["height"], width = (int)json["width"];

		//Tidy these values as appropriate
		CleanRectangleValues(ref height, ref width);

		//Return a new Rectangle as specified by the values in the Json object
		return new Rectangle(height, width);
	}

	return null;
}

Now only perform the .Type check if the json object contains a height/width property and is not null itself:

/// <summary>
/// Public static helper method to convert Json
/// into a Rectangle.
/// </summary>
/// <param name="json">The Json object to transform into a Rectangle.</param>
/// <returns>A Rectangle object based on Json.</returns>
public static Rectangle FromJson(JObject json)
{
	//Check the transformation can actually be performed
	if (json?["width"]?.Type == JTokenType.Integer &&
		json?["height"]?.Type == JTokenType.Integer)
	{
		//Get the height/width from the Json object
		int height = (int)json["height"], width = (int)json["width"];

		//Tidy these values as appropriate
		CleanRectangleValues(ref height, ref width);

		//Return a new Rectangle as specified by the values in the Json object
		return new Rectangle(height, width);
	}

	return null;
}

Adjusted code (‘using static’ within the using clause section) to reduce code further by not fully qualifying enum types:

/// <summary>
/// Public static helper method to convert Json
/// into a Rectangle.
/// </summary>
/// <param name="json">The Json object to transform into a Rectangle.</param>
/// <returns>A Rectangle object based on Json.</returns>
public static Rectangle FromJson(JObject json)
{
	//Check the transformation can actually be performed
	if (json?["width"]?.Type == Integer &&
		json?["height"]?.Type == Integer)
	{
		//Get the height/width from the Json object
		int height = (int)json["height"], width = (int)json["width"];

		//Tidy these values as appropriate
		CleanRectangleValues(ref height, width);

		//Return a new Rectangle as specified by the values in the Json object
		return new Rectangle(height, width);
	}

	return null;
}

This is so very, very cool. There are two ideas on display here; firstly that the ‘?’ can be placed to the right of a reference variable to state the intention that anything to the right of the operator should only be considered if the variable is not null (in this case we also would not fall inside the if statement). Next up, the ‘?’ is applied to say, ‘only check .Type == Integer (a Json JTokenType enum value) if the JObject contains a ‘height/width’ property. If this is null, do not call .Type’. I really like this and can imagine applying this a great deal to simplify code and leave the underlying intention in plain sight, for other developers to see.

Null Conditional Operators with Events

The Null Conditional Operator can also be used to trim down the level of boilerplate code that comes with triggering events in a thread-safe manner, as you can see from the below snippet (which is also using Expression-Bodied method syntax where possible):

#region Event Handling

/// <summary>
/// Outlines a method definition for subscribers to match
/// (that has no return type).
/// </summary>
/// <param name="sender">This will be the Rectangle involved.</param>
/// <param name="e">Any event arguments associated with the event.</param>
public delegate void RectangleFlippedHandler(object sender, EventArgs e);

/// <summary>
/// Event for flipping a Rectangle (functionally does nothing, for 
/// illustration only).
/// </summary>
public event RectangleFlippedHandler RectangleFlipped;

/// <summary>
/// Public method that flips a Rectangle (just fires a vanilla event).
/// </summary>
public void FlipRectangle() => OnRectangleFlipped(EventArgs.Empty);

/// <summary>
/// Protected method that invokes the RectangleFlipped event
/// and sends messages to all listeners (if RectangleFlipped is not null - i.e.
/// they are subscribers - Using the Elvis operator!).
/// </summary>
/// <param name="e">Passed in Event Arguments.</param>
protected void OnRectangleFlipped(EventArgs e) => RectangleFlipped?.Invoke(this, e);

#endregion Event Handling

Exception Filters and Await Changes

Exception Filters can now be applied in C# allowing the developer specific control over when exceptions are caught (or thrown back to the caller). In addition, the ‘await’ keyword can now be used with catch and finally blocks, allowing asynchronous tasks to be kicked off within these scopes:

#region Exception Handling Changes Example

/// <summary>
/// Public method that will cause an exception.
/// </summary>
public async void ExceptionMethod()
{
	try
	{
		//BANG!
		CallExceptionThrowingMethod();
	}
	catch (InvalidOperationException ex) when (ex.InnerException != null) //Only catch here if ex.InnerException is not null, otherwise throw
	{
		//Actually using System.Diagnostics.Debug.WriteLine - Brought in with 'using static'
		WriteLine(ex.Message);
		await LogRectangleMessagesAsync(ex.Message);
	}
	finally
	{
		WriteLine("Finished processing within the ExceptionMethod");
		//Await can be used here also!!!
	}
}

/// <summary>
/// Logs a message to the console after a short delay.
/// </summary>
/// <param name="logMessage">The message to log.</param>
/// <returns>No result.</returns>
private async Task LogRectangleMessagesAsync(string logMessage)
{
	await Task.Delay(3000);
	Console.WriteLine(string.Concat("Logged: ", logMessage));
}

/// <summary>
/// Method that simply throws exceptions.
/// </summary>
private void CallExceptionThrowingMethod()
{
	//Change the exception thrown here to see exception filtering in action within the ExceptionMethod method

	//throw new InvalidOperationException("A configuration exception occurred!");
	throw new InvalidOperationException("An invalid operation was performed!", new InvalidCastException("An invalid cast was performed!"));
}

#endregion Exception Handling Changes Example

Lastly, for reference here are the complete Program and Rectangle class definitions:

using System;
using Newtonsoft.Json.Linq;
using System.Threading.Tasks;
using static Newtonsoft.Json.Linq.JTokenType;
using static System.Diagnostics.Debug;

namespace CSharpSixTest.Shapes
{
    /// <summary>
    /// Outlines the definition for
    /// a Rectangle object.
    /// </summary>
    public class Rectangle
    {
        #region Private Constants

        //The minimum length (as an integer) for any 'side' of a Rectangle
        private const int minimumLengthAllowed = 1;

        //The maximum length (as an integer) for any 'side' of a Rectangle
        private const int maximumLengthAllowed = 20;

        #endregion Private Constants

        #region Getter-Only Auto-Properties

        /// <summary>
        /// Allows access to the 
        /// Rectangles Height.
        /// </summary>
        public int Height { get; }

        /// <summary>
        /// Allows access to the 
        /// Rectangles Width.
        /// </summary>
        public int Width { get; }

        #endregion Getter-Only Auto-Properties

        #region Expression-Bodied Property

        /// <summary>
        /// Returns a value that represents the 
        /// perimeter for this Rectangle.
        /// </summary>
        public int Perimeter => (2 * (Height + Width));

        #endregion Expression-Bodied Property

        #region Constructor

        /// <summary>
        /// Constructor that initialises
        /// this Rectangle. Exceptions use the nameof keyword
        /// to prevent issues whereby variable names change.
        /// </summary>
        /// <param name="height">The height of the Rectangle to create.</param>
        /// <param name="width">The width of the Rectangle to create.</param>
        public Rectangle(int height, int width)
        {
            //Ensure the height value provided falls within the specified limit
            if (height < minimumLengthAllowed || height > maximumLengthAllowed)
            {
                throw new ArgumentOutOfRangeException(nameof(height));
            }

            //Ensure the width value provided falls within the specified limit
            if (width < minimumLengthAllowed || width > maximumLengthAllowed)
            {
                throw new ArgumentOutOfRangeException(nameof(width));
            }

            //If height matches width then we would have a square! Ensure this is pushed back to the caller as an error
            if (height == width)
            {
                throw new ArgumentException("The parameters provided are of the same value (which will make a square!).", nameof(height));
            }

            //Values provided are safe, initialise this object
            Height = height;
            Width = width;
        }

        #endregion Constructor

        #region Expression-Bodied/String Interpolation Overriden Methods

        /// <summary>
        /// Rectangle overriden ToString() method showing an example
        /// of an Expression-Bodied method using String Interpolation.
        /// </summary>
        /// <returns>A string representation for a Rectangle.</returns>
        public override string ToString() => $"Height = { Height }; Width = { Width };"; //Values embedded in statement - Very terse and easy to understand (less error prone)

        #endregion Expression-Bodied/String Interpolation Overriden Methods

        #region Public Methods

        /// <summary>
        /// Convert this Rectangle to a Json object.
        /// </summary>
        /// <returns>A Json object based on a particular Rectangle instance.</returns>
        public JObject ToJson() => new JObject() {["height"] = Height, ["width"] = Width };

        #endregion Public Methods

        #region Public Static Methods

        /// <summary>
        /// Public method that returns a Rectangle with a
        /// random height and width (within set parameters).
        /// </summary>
        /// <returns>A Rectangle with a random height and width between the allowed values.</returns>
        public static Rectangle GetRandomRectangle()
        {
            //Create an rng object and generate a random height/width
            Random rng = new Random();

            int height = rng.Next(minimumLengthAllowed, maximumLengthAllowed + 1), width = rng.Next(minimumLengthAllowed, maximumLengthAllowed + 1);

            //Bit of protection here, increment/decrement the height just to prevent the Rectangle from being a Square (if height matches width)
            CleanRectangleValues(ref height, width);

            //Generate the new Rectangle and return it to the caller
            return new Rectangle(height, width);
        }

        /// <summary>
        /// Public static helper method to convert Json
        /// into a Rectangle.
        /// </summary>
        /// <param name="json">The Json object to transform into a Rectangle.</param>
        /// <returns>A Rectangle object based on Json.</returns>
        public static Rectangle FromJson(JObject json)
        {
            //Check the transformation can actually be performed
            if (json?["width"]?.Type == Integer &&
                json?["height"]?.Type == Integer)
            {
                //Get the height/width from the Json object
                int height = (int)json["height"], width = (int)json["width"];

                //Tidy these values as appropriate
                CleanRectangleValues(ref height, width);

                //Return a new Rectangle as specified by the values in the Json object
                return new Rectangle(height, width);
            }

            return null;
        }

        #endregion Public Static Methods

        #region Private Static Helpers

        /// <summary>
        /// Private static helper method that increments/decrements
        /// the height value provided based on the width (if they match). 
        /// Helps prevent making 'Squares'.
        /// </summary>
        /// <param name="height">A Rectangles prospective height value (passed by ref).</param>
        /// <param name="width">A Rectangles prospective width value.</param>
        private static void CleanRectangleValues(ref int height, int width)
        {
            //If height matches width see if we need to increment or decrement height (so we end up with values that make a valid Rectangle)
            if (height == width)
            {
                if (height != maximumLengthAllowed)
                {
                    height++;
                }
                else
                {
                    height--;
                }
            }
        }

        #endregion Private Static Helpers

        #region Event Handling

        /// <summary>
        /// Outlines a method definition for subscribers to match
        /// (that has no return type).
        /// </summary>
        /// <param name="sender">This will be the Rectangle involved.</param>
        /// <param name="e">Any event arguments associated with the event.</param>
        public delegate void RectangleFlippedHandler(object sender, EventArgs e);

        /// <summary>
        /// Event for flipping a Rectangle (functionally does nothing, for 
        /// illustration only).
        /// </summary>
        public event RectangleFlippedHandler RectangleFlipped;

        /// <summary>
        /// Public method that flips a Rectangle (just fires a vanilla event).
        /// </summary>
        public void FlipRectangle() => OnRectangleFlipped(EventArgs.Empty);

        /// <summary>
        /// Protected method that invokes the RectangleFlipped event
        /// and sends messages to all listeners (if RectangleFlipped is not null - i.e.
        /// they are subscribers - Using the Elvis operator!).
        /// </summary>
        /// <param name="e">Passed in Event Arguments.</param>
        protected void OnRectangleFlipped(EventArgs e) => RectangleFlipped?.Invoke(this, e);

        #endregion Event Handling

        #region Exception Handling Changes Example

        /// <summary>
        /// Public method that will cause an exception.
        /// </summary>
        public async void ExceptionMethod()
        {
            try
            {
                //BANG!
                CallExceptionThrowingMethod();
            }
            catch (InvalidOperationException ex) when (ex.InnerException != null) //Only catch here if ex.InnerException is not null, otherwise throw
            {
                //Actually using System.Diagnostics.Debug.WriteLine - Brought in with 'using static'
                WriteLine(ex.Message);
                await LogRectangleMessagesAsync(ex.Message);
            }
            finally
            {
                WriteLine("Finished processing within the ExceptionMethod");
                //Await can be used here also!!!
            }
        }

        /// <summary>
        /// Logs a message to the console after a short delay.
        /// </summary>
        /// <param name="logMessage">The message to log.</param>
        /// <returns>No result.</returns>
        private async Task LogRectangleMessagesAsync(string logMessage)
        {
            await Task.Delay(3000);
            Console.WriteLine(string.Concat("Logged: ", logMessage));
        }

        /// <summary>
        /// Method that simply throws exceptions.
        /// </summary>
        private void CallExceptionThrowingMethod()
        {
            //Change the exception thrown here to see exception filtering in action within the ExceptionMethod method

            //throw new InvalidOperationException("A configuration exception occurred!");
            throw new InvalidOperationException("An invalid operation was performed!", new InvalidCastException("An invalid cast was performed!"));
        }

        #endregion Exception Handling Changes Example
    }
}
using System;
using CSharpSixTest.Shapes;

//Bring the static members of the Rectangle and Console types directly into scope (meaning they don't need to be fully qualified)
using static CSharpSixTest.Shapes.Rectangle;
using static System.Console;
using Newtonsoft.Json.Linq;

namespace CSharpSixTest
{
    /// <summary>
    /// Main Program Class.
    /// </summary>
    class Program
    {
        /// <summary>
        /// Main method for this test drive application.
        /// </summary>
        /// <param name="args">Optional input arguments</param>
        static void Main(string[] args)
        {
            //Create a new random Rectangle calling the static Rectangle class GetRandomRectangle method (notice that the type does not to be included here)
            Rectangle newRectangle = GetRandomRectangle();

            //Use static members of System.Console without needed to fully qualify them (with type)
            WriteLine(newRectangle.Height);
            WriteLine(newRectangle.Width);
            WriteLine(newRectangle);
            WriteLine(newRectangle.Perimeter);

            //Rectangle to Json call
            JObject rectangleJson = newRectangle.ToJson();

            //Rectangle event hookup (to anonymous method)
            newRectangle.RectangleFlipped += (sender, e) =>
            {
                if (sender is Rectangle)
                {
                    WriteLine($"Flipped Rectangle: { sender as Rectangle }.");
                }
            };

            //Trigger the event
            newRectangle.FlipRectangle();

            //Pass null/incorrect formed JObjects before passing a valid JObject to convert back to a rectangle
            Rectangle rect = FromJson(null);
            Rectangle rect2 = FromJson(new JObject());
            Rectangle rect3 = FromJson(rectangleJson);

            WriteLine(rect3);

            //Trigger an exception (change Rectangle class to catch exception here)
            try
            {
                newRectangle.ExceptionMethod();
            }
            catch (InvalidOperationException ex)
            {
                WriteLine(ex.Message);
            }

            //Complete! Invalid Operation Exception will show after this in the current configuration
            WriteLine("Test Run Complete");

            //Await user response
            ReadKey();
        }
    }
}

Have fun exploring the new features and bye for now.

Buffering…

Hi all,

A quick apology as I’ve stalled a little on adding new content. I’ve been undertaking some new projects at work and home which is consuming much of my time. I’ll aim to get something new pushed up in the coming week or so.

Signing off for now!

Code Project: Epic Quest! Basic Architecture

This project has been moving along at a nice, steady pace; here’s a run-down of the progress and first round of decisions I’ve made surrounding the games architecture.

I don’t plan on showing every single line of code. Instead, I’ll focus on the core structural work I’ve done and just list out details on a few of the classes that I’ve been working on. I’ll happily make the project available at the end of all this should anyone want to take a full look at the code.

Starting off with the very basics, you’ll remember me saying that I used to love Hero Quest as a kid (and to be honest I think I’d have a better appreciation of the game now; I just used to stand over all of the figures and wind my older brother up!). A core concept of Hero Quest was the attack and defence dice, with the amount of dice being rolled dependant on skills, weapons, augmentations and abilities. Here’s my first implementation of Green (weakest), Blue (middle-of-the-road) and Red (bad-ass) Die classes which hang off an abstract, base Die class.

Current Die Class Hierarchy.

Current Die Class Hierarchy.

As I stated before, I tend to create a fairly fleshed out class hierarchy before deciding whether any fat needs to get trimmed. In this case, I removed the AttackDie and DefenceDie classes and Attack/Defence Die class variants for each colour. Instead, I’ve opted for each dice to support ‘Miss’ (will be renamed to ‘Fail’), ‘SinglePoint’, ‘DoublePoint’, ‘TriplePoint’ and ‘CriticalPoint’ results. The ‘Point’ results will be utilised for determining both attack and defence roll values. The Green Die is the weakest of the three and contains the most ‘Miss’ results and only ‘SinglePoint’ attack/defence results. The Blue Die has only two ‘Miss’ results and supports ‘SinglePoint’ and ‘DoublePoint’ result values. Finally, the Red Die represents the strongest attack and defence clout, having (as per the Blue Die) two ‘Miss’ results and ‘DoublePoint’, ‘TriplePoint’ and ‘CriticalPoint’ results. The various weapons and armour will allow the players to roll various amounts of these dice (monsters, although not using items per say, will simply utilise a fixed amount of dice for attack and defence, unless I implement some kind of ability system for them in addition to the heroes).

Here, as an example, is the current code behind the Die base class and the Red Die (just for illustration purposes; the code for the Green Die/Blue Die is of course very similar due to its affiliation with the Die base class).

using EpicQuest.GameEnums;

namespace EpicQuest.Models
{
    /// <summary>
    /// Base class for all Epic Quest Die objects.
    /// </summary>
    internal abstract class Die
    {
        #region Abstract Members

        /// <summary>
        /// Each Die must implement its own array of
        /// DieFace enum values (i.e. the possible results
        /// supported by the Die in question).
        /// </summary>
        internal abstract DieFace[] DieFaces { get; }

        #endregion Abstract Members
    }
}
using EpicQuest.GameEnums;

namespace EpicQuest.Models.Dice
{
    /// <summary>
    /// Internal Sealed Class representing the strongest 
    /// dice type in Epic Dungeon. This will only be assigned
    /// to the strongest weapons/armour in the game.
    /// </summary>
    internal sealed class RedDie : Die
    {
        #region Private Read Only Data Fields

        //Represents the Red Die 'faces' (aka the possible results from 'rolling' the die)
        private readonly DieFace[] dieFaces;

        #endregion Private Read Only Fields

        #region Overriden Properties

        /// <summary>
        /// Allow access to the die faces (results)
        /// that make up this dice.
        /// </summary>
        internal override DieFace[] DieFaces
        {
            get 
            {
                return dieFaces;
            }
        }

        #endregion Overriden Properties

        #region Constructor

        /// <summary>
        /// RedDie Constructor that configures
        /// the results available on this Die.
        /// </summary>
        internal RedDie()
        {
            dieFaces = new DieFace[6] { DieFace.Miss, DieFace.DoublePoint, DieFace.TriplePoint, DieFace.Miss, DieFace.TriplePoint, DieFace.CriticalPoint };
        }

        #endregion Constructor
    }
}

Before I go any further….

Tangent alert!!! For anyone who doesn’t know what Hero Quest is, or just wants a refresher on how awesome that game was, check out the 1991 commercial (I was 7; imagine how insane this was!).

Shameless plug also for Board James (aka the Angry Video Game Nerd), here’s a link to his Hero Quest episode for kicks.

So, I could comfortably sit here and fill (I mean FILL!) this post with videos about board games, like this, that I’d happily sit and burn hours playing…but I’d quite like for everyone to continue reading these posts, so I’ll rein that urge right back in (for now)! I’m not promising anything though; I could well go full geek again with zero notice.

Dice are now in tow…Good start I hear you say! Well, we need something that will actually use the Dice – To that end I bring you a Weapon and Armour class.

Current Weapon/Armour Class Hierarchy.

Current Weapon/Armour Class Hierarchy.

In the current state, the Weapon class is a little less fleshed-out than Armour class. These classes implement a handful of very lightweight interfaces supporting the following concepts:

  • The object supports a List of Die objects (i.e. we have secured a contract stating any object using the IRollsDice interface will support this kind of member)
  • The object should be treated as a piece of ‘treasure’ in its own right. This is represented by supporting a GoldValue integer property.
  • The Weapon and Armour classes support independent interfaces enforcing support for Weapon/Armour Types (i.e. Item Types and which ‘Slots’ Armour fills).

Below is the full implementation, well the current implementation anyway, of both of these classes.

using EpicQuest.GameEnums;
using EpicQuest.Interfaces;
using EpicQuest.Models.Dice;
using System;
using System.Collections.Generic;
using System.Linq;

namespace EpicQuest.Models
{
    /// <summary>
    /// Internal Class (not yet sealed, not sure of the plans here)
    /// representing a piece of Armour in Epic Quest.
    /// </summary>
    internal class Armour : IHeroArmour, ITreasure
    {
        #region Constant Members

        //Constants that keep a track of the level 'boundaries' for item types (based on the HeroDefensiveItemType underlying byte value).
        //This system does indeed involve some manual maintenance of the enum types/these values but the engine code found in the 
        //GetDefensiveItemMappings method should take care of the rest
        private const int levelOneMax = 6, levelTwoMax = 15, levelThreeMax = 24, levelFourMax = 26, levelFiveMax = 28, levelMax = 5;

        #endregion Constant Members

        #region Private Data Fields

        //A list of 'dice' that get rolled (in defence) for any hero 'wearing' this Armour
        private List<Die> dice = new List<Die>();

        //Enum values that represent the Armour Type and what 'Body Slot' (i.e. Head, Chest) the Armour takes up
        private HeroDefensiveItemType defensiveItemType = HeroDefensiveItemType.None;
        private HeroDefensiveItemSlotType defensiveItemSlotType = HeroDefensiveItemSlotType.None;

        #endregion Private Data Fields

        #region ITreasure Interface Support (Properties)

        /// <summary>
        /// Return the GoldValue of this particular
        /// piece of Armour (currently fixed at 5).
        /// </summary>
        public int GoldValue
        {
            get
            {
                return 5;
            }
        }

        #endregion ITreasure Interface Support (Properties)

        #region IHeroArmour Interface Support (Properties)

        /// <summary>
        /// Provides access to the Armour Type
        /// associated with this particular piece of Armour.
        /// </summary>
        public HeroDefensiveItemType DefensiveItemType
        {
            get
            {
                return defensiveItemType;
            }
            set
            {
                defensiveItemType = value;

                //Reset the Dice associated with this piece of Armour (based on Type)
                Dice = GetDiceBasedOnDefensiveItemType(value);
            }
        }

        /// <summary>
        /// Provides access to the Armour Type Slot
        /// associated with this particular piece of Armour.
        /// </summary>
        public HeroDefensiveItemSlotType DefensiveItemTypeSlot
        {
            get
            {
                return defensiveItemSlotType;
            }
            set
            {
                defensiveItemSlotType = value;
            }
        }

        #endregion IHeroArmour Interface Support (Properties)

        #region IRollsDice Interface Support (Properties)

        /// <summary>
        /// Provides access to the Defence Dice
        /// associated with this particular piece of Armour.
        /// </summary>
        public List<Die> Dice
        {
            get
            {
                return dice;
            }
            set
            {
                dice = value;
            }
        }

        #endregion IRollsDice Interface Support (Properties)

        #region Static Data Fields (Armour Mappings)

        //Private static backing dictionary (for all classes to use) that provides a mapping 'table' on Armour Types to Armour Slots (and the level of these Armour Types)
        private static Dictionary<KeyValuePair<HeroDefensiveItemType, HeroDefensiveItemSlotType>, int> armourMappings;

        #endregion Static Data Fields (Armour Mappings)

        #region Static Properties (Armour Mappings)

        /// <summary>
        /// Allows access to the static Armour Mapping
        /// dictionary so other classes can view Armour Type,
        /// Armour Slot to Level mappings (so Armour can be placed into
        /// the right slots on a Hero/to check the hero is of the
        /// appropriate level to wear a piece of Armour.
        /// </summary>
        internal static Dictionary<KeyValuePair<HeroDefensiveItemType, HeroDefensiveItemSlotType>, int> ArmourMappings
        {
            get
            {
                return armourMappings;
            }
            private set
            {
                armourMappings = value;
            }
        }

        #endregion Static Properties (Armour Mappings)

        #region Static Constructor

        /// <summary>
        /// Static constructor that fires on first use of this class
        /// to setup Armour Types/Slots and Level mappings.
        /// </summary>
        static Armour()
        {
            armourMappings = GetDefensiveItemMappings();
        }

        #endregion Static Constructor

        #region Internal Static Methods
        
        /// <summary>
        /// Internal static method that returns a 'Slot Type'
        /// based on an Armour Type.
        /// </summary>
        /// <param name="itemType">The Armour Type to inspect.</param>
        /// <returns>The Slot Type this piece of Armour belongs to.</returns>
        internal static HeroDefensiveItemSlotType GetSlotTypeBasedOnArmourType(HeroDefensiveItemType itemType)
        {
            switch (itemType)
            {
                case HeroDefensiveItemType.ClothTunic:
                case HeroDefensiveItemType.LeatherChestPiece:
                case HeroDefensiveItemType.NoviceMagicianRobe:
                case HeroDefensiveItemType.NoviceRobeOfSkulls:
                case HeroDefensiveItemType.AdeptMagicianDragonSkinRobe:
                case HeroDefensiveItemType.AdeptRobeOfDemonSkulls:
                case HeroDefensiveItemType.ChainMailChestPiece:
                case HeroDefensiveItemType.DragonSkinChestPiece:
                case HeroDefensiveItemType.MasterworkPlateChestPiece:
                case HeroDefensiveItemType.BloodStainedMithralArmour:
                case HeroDefensiveItemType.BloodStainedMithralRobe:
                    {
                        return HeroDefensiveItemSlotType.Chest;
                    }
                case HeroDefensiveItemType.LeatherHelm:
                case HeroDefensiveItemType.ChainMailHelm:
                case HeroDefensiveItemType.MasterworkPlateHelm:
                    {
                        return HeroDefensiveItemSlotType.Head;
                    }
                case HeroDefensiveItemType.LeatherGloves:
                case HeroDefensiveItemType.ChainMailGloves:
                case HeroDefensiveItemType.MasterworkPlateGloves:
                    {
                        return HeroDefensiveItemSlotType.Hands;
                    }
                case HeroDefensiveItemType.LeatherBoots:
                case HeroDefensiveItemType.ChainMailBoots:
                case HeroDefensiveItemType.MasterworkPlateBoots:
                    {
                        return HeroDefensiveItemSlotType.Feet;
                    }
                case HeroDefensiveItemType.LeatherPants:
                case HeroDefensiveItemType.ChainMailPants:
                case HeroDefensiveItemType.MasterworkPlatePants:
                    {
                        return HeroDefensiveItemSlotType.Legs;
                    }
                case HeroDefensiveItemType.SilverNecklace:
                case HeroDefensiveItemType.GoldNecklace:
                    {
                        return HeroDefensiveItemSlotType.Necklace;
                    }
                case HeroDefensiveItemType.SilverRing:
                case HeroDefensiveItemType.GoldRing:
                    {
                        return HeroDefensiveItemSlotType.Ring;
                    }
                case HeroDefensiveItemType.None:
                default:
                    {
                        return HeroDefensiveItemSlotType.None;
                    }
            }
        }

        /// <summary>
        /// Internal static method that returns the 'Dice' that
        /// can be used based on the type of Armour specified.
        /// </summary>
        /// <param name="itemType">The Armour Type to inspect.</param>
        /// <returns>A List of Dice (Die) objects that can be rolled based on the Armour Type specified.</returns>
        internal static List<Die> GetDiceBasedOnDefensiveItemType(HeroDefensiveItemType itemType)
        {
            List<Die> defensiveDice = new List<Die>();

            switch (itemType)
            {
                default:
                case HeroDefensiveItemType.ClothTunic:
                case HeroDefensiveItemType.LeatherHelm:
                case HeroDefensiveItemType.LeatherGloves:
                case HeroDefensiveItemType.LeatherBoots:
                case HeroDefensiveItemType.LeatherPants:
                case HeroDefensiveItemType.SilverNecklace:
                case HeroDefensiveItemType.SilverRing:
                    {
                        defensiveDice.Add(new GreenDie());
                    }
                    break;
                case HeroDefensiveItemType.LeatherChestPiece:
                case HeroDefensiveItemType.GoldNecklace:
                case HeroDefensiveItemType.GoldRing:
                    {
                        defensiveDice.AddRange(new Die[] { new GreenDie(), new GreenDie() });
                    }
                    break;
            }

            return defensiveDice;
        }

        #endregion Internal Static Methods

        #region Private Static Methods

        /// <summary>
        /// Private static method that configures (and returns a dictionary representing)
        /// Armour Type to Armour Slot mappings (with a value denoting what level a hero
        /// needs to be to wear a piece of Armour).
        /// </summary>
        /// <returns>A dictionary that represents Armour Type to Armour Slot mappings (with level information).</returns>
        private static Dictionary<KeyValuePair<HeroDefensiveItemType, HeroDefensiveItemSlotType>, int> GetDefensiveItemMappings()
        {
            Dictionary<KeyValuePair<HeroDefensiveItemType, HeroDefensiveItemSlotType>, int> mappings = new Dictionary<KeyValuePair<HeroDefensiveItemType, HeroDefensiveItemSlotType>, int>();

            //Temporary try/catch (put in during development as this piece of code evolves)
            try
            {
                //There are currently '5' (or whatever levelMax is set to) levels of Armour Items present in the game - Loop 5 times to capture all Armour Types
                for (int level = 1; level <= levelMax; level++)
                {
                    //Get values in the HeroDefensiveItemType enum and get the ones belong to the current level (based on for loop)
                    Enum.GetValues(typeof(HeroDefensiveItemType)).Cast<HeroDefensiveItemType>().Where(item => GetLevelConditionFilter(level, item)).ToList<HeroDefensiveItemType>().ForEach(item =>
                    {
                        //Store a reference, in the mappings dictionary, to the Armour Type, the Slot Type the Armour belongs to (via the GetSlotTypeBasedOnArmourType method) and the level this
                        //item belongs to (represented by the level variable)
                        HeroDefensiveItemSlotType slotType = GetSlotTypeBasedOnArmourType(item);
                        mappings.Add(new KeyValuePair<HeroDefensiveItemType, HeroDefensiveItemSlotType>(item, slotType), level);   
                    });
                }
            }
            catch (Exception ex)
            {
                //Write errors to the console (to be removed) - No need to interrupt the flow of the game for now (broken mappings = broken game, so the player would need to close anyway)
                Console.WriteLine(ex.Message);
            }

            return mappings;
        }

        /// <summary>
        /// Private static method that returns a boolean determining in the 
        /// Armour Type specified belongs to the current level value passed in.
        /// </summary>
        /// <param name="level">The level to check against (does the Armour specified belong to this level).</param>
        /// <param name="item">The Armour Type to check.</param>
        /// <returns>If the Armour Type belongs to the specified level then true, otherwise false. An Armour Type of HeroDefensiveItemType.None will always result in false.</returns>
        private static bool GetLevelConditionFilter(int level, HeroDefensiveItemType item)
        {
            //When using this filter an Armour Type of None should never be included, return false
            if (item == HeroDefensiveItemType.None)
            {
                return false;
            }

            //Only return true if an Armour Types underlying byte type falls between the level min/max limits specified (by constants in this class)
            switch (level)
            {
                default:
                case 1:
                    {
                        return ((byte)item > 0 && (byte)item <= levelOneMax);
                    }
                case 2:
                    {
                        return ((byte)item > levelOneMax && (byte)item <= levelTwoMax);
                    }
                case 3:
                    {
                        return ((byte)item > levelTwoMax && (byte)item <= levelThreeMax);
                    }
                case 4:
                    {
                        return ((byte)item > levelThreeMax && (byte)item <= levelFourMax);
                    }
                case 5:
                    {
                        return ((byte)item > levelFourMax && (byte)item <= levelFiveMax);
                    }
            }
        }

        #endregion Private Static Methods
    }
}
using EpicQuest.GameEnums;
using EpicQuest.Interfaces;
using EpicQuest.Models.Dice;
using System.Collections.Generic;

namespace EpicQuest.Models
{
    /// <summary>
    /// Internal Class (not yet sealed, not sure of the plans here)
    /// representing a Weapon in Epic Quest.
    /// </summary>
    internal class Weapon : ITreasure, IHeroWeapon
    {
        #region Private Data Fields

        //A list of 'dice' that get rolled (in attack) for any hero 'using' this Weapon
        private List<Die> dice = new List<Die>();

        //An Enum value that represent the Weapon Type being used
        private HeroOffensiveItemType offensiveItemType = HeroOffensiveItemType.Fists;

        #endregion Private Data Fields

        #region IRollsDice Interface Support (Properties)

        /// <summary>
        /// Provides access to the Attack Dice
        /// associated with this particular Weapon.
        /// </summary>
        public List<Die> Dice
        {
            get
            {
                return dice;
            }
            set
            {
                dice = value;
            }
        }

        #endregion IRollsDice Interface Support (Properties)

        #region ITreasure Interface Support (Properties)

        /// <summary>
        /// Return the GoldValue of this particular
        /// Weapon (currently fixed at 5). 
        /// </summary>
        public int GoldValue
        {
            get
            {
                return 5;
            }
        }

        #endregion ITreasure Interface Support (Properties)

        #region IHeroWeapon Interface Support (Properties)

        /// <summary>
        /// Provides access to the Weapon Type
        /// associated with this particular Weapon.
        /// </summary>
        public HeroOffensiveItemType OffensiveItemType
        {
            get 
            {
                return offensiveItemType; 
            }
	        set 
	        {
                offensiveItemType = value;

                //Reset the Dice associated with this Weapon (based on Type)
                Dice = GetDiceBasedOnOffensiveItemType(offensiveItemType);
	        }
        }

        #endregion IHeroWeapon Interface Support (Properties)

        #region Constructor

        /// <summary>
        /// Constructor for the Weapon Class
        /// that just sets the Weapon Type currently.
        /// </summary>
        /// <param name="itemType">The Weapon Type for this particular Weapon.</param>
        public Weapon(HeroOffensiveItemType itemType = HeroOffensiveItemType.Fists)
        {
            OffensiveItemType = itemType;
        }

        #endregion Constructor

        #region Internal Static Methods

        /// <summary>
        /// Internal static method that, based on the Weapon Type
        /// provided, returns the appropriate Attack Dice.
        /// </summary>
        /// <param name="itemType">The Weapon Type to inspect.</param>
        /// <returns>The dice that can be rolled based on the Weapon Type specified.</returns>
        internal static List<Die> GetDiceBasedOnOffensiveItemType(HeroOffensiveItemType itemType)
        {
            List<Die> offensiveDice = new List<Die>();

            switch (itemType)
            {
                default:
                case HeroOffensiveItemType.Fists:
                case HeroOffensiveItemType.RustyDagger:
                case HeroOffensiveItemType.RustyMace:
                case HeroOffensiveItemType.RustyShortSword:
                    {
                        offensiveDice.Add(new GreenDie());
                    }
                    break;
                case HeroOffensiveItemType.RustyBastardSword:
                    {
                        offensiveDice.AddRange(new Die[] { new GreenDie(), new GreenDie() });
                    }
                    break;
                case HeroOffensiveItemType.SilverHexDagger:
                case HeroOffensiveItemType.MagicMissile:
                    {
                        offensiveDice.AddRange(new Die[] { new GreenDie(), new BlueDie() });
                    }
                    break;
                case HeroOffensiveItemType.FlameTorch:
                case HeroOffensiveItemType.Freeze:
                case HeroOffensiveItemType.FineBarbedWireMace:
                case HeroOffensiveItemType.JaggedSword:
                    {
                        offensiveDice.AddRange(new Die[] { new GreenDie(), new GreenDie(), new BlueDie() });
                    }
                    break;
                case HeroOffensiveItemType.Disolve:
                case HeroOffensiveItemType.LegendaryBastardSword:
                    {
                        offensiveDice.AddRange(new Die[] { new BlueDie(), new RedDie() });
                    }
                    break;
            }

            return offensiveDice;
        }

        #endregion Internal Static Methods
    }
}

The key point that I want to focus in on at the moment is that each class implements an interface that states that they ‘support’ dice.


#region IRollsDice Interface Support (Properties)

/// <summary>
/// Provides access to the Defence Dice
/// associated with this particular piece of Armour.
/// </summary>
public List<Die> Dice
{
	get
	{
		return dice;
	}
	set
	{
		dice = value;
	}
}

#endregion IRollsDice Interface Support (Properties)

In addition to this, the classes have fully fledged members to determine what combinations of dice are associated with the Weapon and Armour types available (and what slots the Armour Types relate to).

At this point, we have dice to roll to reflect offensive and defensive abilities as well as Weapons and Armour that utilise these dice. Now we have these objects ready for use in our game we really need to code the hero characters to use these items. Below is another starter definition for our character based classes:

Current Character Class Hierarchy.

Current Character Class Hierarchy.

To back this class diagram up, here is a first implementation of the Hero base class and one example of a semi-bulked out Brawler class. Keep in mind this is for pure illustration purposes only; some of this code, particularly the property for defence dice, is a little nightmarish in its current form! However, I’ve resolved to show you things as they evolve and if they are, for want of a better word, a bit ‘crap’ to start with I’d rather show you and just mention it along the way. It essentially boils down to this being an iterative process and some pieces of code will always simply be in play for conceptual purposes (especially at this stage).

using EpicQuest.Interfaces;
using System;
using System.Collections.Generic;

namespace EpicQuest.Models
{
    /// <summary>
    /// Base class for all hero types.
    /// </summary>
    internal abstract class Hero : GameCharacter, ICombatant
    {
        #region Abstract Properties (ICombatant Interface Support)

        /// <summary>
        /// The heros health (overriden for each Hero).
        /// </summary>
        public abstract int Health { get; set; }
        
        /// <summary>
        /// The dice this hero can roll for defence
        /// (based on abilities/armour etc). Must be
        /// overriden for each particular hero.
        /// </summary>
        public abstract List<Die> DefenceDice { get; }
        
        /// <summary>
        /// The dice this hero can roll for offence
        /// (based on weapons/abilities). Must be 
        /// overriden for each particular hero.
        /// </summary>
        public abstract List<Die> AttackDice { get; }

        #endregion Abstract Properties (ICombatant Interface Support)

        #region Abstract Methods

        /// <summary>
        /// Abstract member that must be overriden for each
        /// particular hero (and will refresh the attack/defence
        /// dice state for a particular hero).
        /// </summary>
        public abstract void RefreshDiceState();

        #endregion Abstract Methods
    }
}
using System.Collections.Generic;

namespace EpicQuest.Models
{
    /// <summary>
    /// Implementation of the Brawler hero type.
    /// </summary>
    internal sealed class Brawler : Hero
    {
        #region Private Data Fields

        //The characters starting health value
        private int health = 10;

        //Fields that denote a heroes head and chest slot armour types and a base weapon for this hero to use. This is implemented in its current for for test purposes only
        private Armour headSlot = new Armour() { DefensiveItemType = GameEnums.HeroDefensiveItemType.LeatherHelm, DefensiveItemTypeSlot = GameEnums.HeroDefensiveItemSlotType.Head };
        private Armour chestSlot = new Armour() { DefensiveItemType = GameEnums.HeroDefensiveItemType.ChainMailChestPiece, DefensiveItemTypeSlot = GameEnums.HeroDefensiveItemSlotType.Chest };
        private Weapon heroWeapon = new Weapon(GameEnums.HeroOffensiveItemType.FineBarbedWireMace);

        #endregion Private Data Fields

        #region ICombatant (abstract overrides) Interface Support

        /// <summary>
        /// Access to the characters health (to reduce 
        /// during combat for example).
        /// </summary>
        public override int Health
        {
            get
            {
                return health;
            }
            set
            {
                health = value;
            }
        }

        /// <summary>
        /// Access to this characters defence dice
        /// for rolling during combat.
        /// </summary>
        public override List<Die> DefenceDice
        {
            get
            {
                //THIS IS NOT PERMANENT - FOR DEMONSTRATION PURPOSES ONLY (NIGHTMARISH CODE ALERT - WOULDN'T WANT A NEW LIST EACH TIME)
                List<Die> currentDefenceDice = new List<Die>(headSlot.Dice.Count + chestSlot.Dice.Count);
                currentDefenceDice.AddRange(headSlot.Dice);
                currentDefenceDice.AddRange(chestSlot.Dice);

                return currentDefenceDice;
            }
        }

        /// <summary>
        /// Access to this characters defence dice
        /// for rolling during combat.
        /// </summary>
        public override List<Die> AttackDice
        {
            get
            {
                return heroWeapon.Dice;
            }
        }

        /// <summary>
        /// Overriden method that will inspect this heroes 
        /// state and refresh the dice associated with attack/defence
        /// based on the items in scope.
        /// </summary>
        public override void RefreshDiceState()
        {
            //TODO
        }

        #endregion ICombatant (abstract overrides) Interface Support
    }
}

There are still quite a few details to take care of here, but this very simple class structure enables us to set-up and test a combat scenario, which I’ll take you through in a moment. Before moving on however, I want to illustrate two other parts of the class diagram (although I’m not going to go through the details yet) showing you the enumerations currently written and other miscellaneous parts of the code base. We’ll talk about these areas of the code base in future posts regardless.

Current Enum Structure.

Current Enum Structure.

Current Misc Class Hierarchy.

Current Misc Class Hierarchy.

Finally, as an introduction to the piece of combat code previously mentioned, here is a phase one representation of a Dungeon and Room class. The plan here is to provide a Dungeon that contains a random number of rooms and pieces of content (classes implementing IRoomContent) for the adventurers to interact with. Clearing all of the rooms, by killing monsters and collecting treasure, outlines the win condition for the game.

Current Dungeon/Room Class Hierarchy.

Current Dungeon/Room Class Hierarchy.

using EpicQuest.Interfaces;
using System;
using System.Collections.Generic;
using System.Linq;

namespace EpicQuest.Models.Dungeon
{
    /// <summary>
    /// Internal Sealed class that represents the Rooms
    /// in a Dungeon (filled with monsters and treasure).
    /// </summary>
    internal sealed class Room : IUniqueItem
    {
        #region Private Data Fields

        //A Rooms unique reference (should a room need to be uniquely identified) and a List of Room Content
        private readonly Guid uniqueRef = Guid.NewGuid();
        private List<IRoomContent> roomFeatures = new List<IRoomContent>();

        #endregion Private Data Fields

        #region Properties

        /// <summary>
        /// Access to this Rooms Unique Reference.
        /// </summary>
        public Guid UniqueRef
        {
            get
            {
                return uniqueRef;
            }
        }

        /// <summary>
        /// Helper property that checks to see if any 
        /// remaining Room Content is of type Monster.
        /// </summary>
        internal bool RoomClearedOfMonsters
        {
            get
            {
                if (roomFeatures.Any(feature => feature is Monster))
                {
                    return false;
                }

                return true;
            }
        }

        /// <summary>
        /// Access to a Rooms Content Features.
        /// </summary>
        internal List<IRoomContent> RoomFeatures 
        { 
            get
            {
                return roomFeatures;
            }
            private set
            {
                if (value != null && value.Count > 0)
                {
                    roomFeatures = value;
                }
            }
        }

        #endregion Properties

        #region Constructors

        /// <summary>
        /// Room constructor that allows a Room to be populated
        /// with a single piece of content (or an array of content).
        /// </summary>
        /// <param name="features">The content to place in the Room (single piece or an array of).</param>
        internal Room(params IRoomContent[] features)
            : this (features.ToList())
        {

        }

        /// <summary>
        /// Room constructor that allows a Room to be populated
        /// with a List of content.
        /// </summary>
        /// <param name="features">A list of content to place in the Room.</param>
        internal Room(List<IRoomContent> features)
        {
            if (features != null && features.Count > 0)
            {
                RoomFeatures = features;
            }
        }

        #endregion Constructors

        #region Internal Methods

        /// <summary>
        /// Internal method that allows a piece of content/multiple pieces
        /// of content to be added to this particular Room.
        /// </summary>
        /// <param name="features">A single piece of content/array of content pieces to add to the Room.</param>
        internal void AddContentToRoom(params IRoomContent[] features)
        {
            if (features != null && features.Count() > 0)
            {
                foreach (IRoomContent item in features)
                {
                    roomFeatures.Add(item);
                }
            }
        }

        /// <summary>
        /// Internal method that allows a piece of content/multiple pieces
        /// of content to be removed from this particular Room.
        /// </summary>
        /// <param name="features">>A single piece of content/array of content pieces to removed from the Room.</param>
        internal void RemoveContentFromRoom(params IRoomContent[] features)
        {
            if (features != null && features.Count() > 0)
            {
                foreach (IRoomContent item in features)
                {
                    roomFeatures.Remove(item);
                }
            }
        }

        #endregion Internal Methods

        #region Enumerator

        /// <summary>
        /// Enumerator that allows external classes
        /// to more easily iterate over the Room Features in this
        /// Room (depending on a developers preferences).
        /// </summary>
        /// <returns>The RoomFeatures Enumerator.</returns>
        public List<IRoomContent>.Enumerator GetEnumerator()
        {
            return RoomFeatures.GetEnumerator();
        }

        #endregion Enumerator

        #region Internal Static Methods

        /// <summary>
        /// Internal static helper method that generates and returns a random
        /// List of Room Content.
        /// </summary>
        /// <param name="contentAmountSeed">A seed to help determine the amount of pieces to generate.</param>
        /// <returns>A random List of Room Content.</returns>
        internal static List<IRoomContent> GenerateRandomRoomContent(int contentAmountSeed)
        {
            //CURRENTLY HARD CODED TO RETURN TWO MONSTERS AS CONTENT (COMBAT TEST)
            return new List<IRoomContent>(new IRoomContent[] { new Kobold(), new Skeleton() });
        }

        #endregion Internal Static Methods
    }
}
using System;
using System.Collections.Generic;
using System.Linq;

namespace EpicQuest.Models.Dungeon
{
    /// <summary>
    /// Class that represents a dungeon that adventurers
    /// can 'quest' through with rooms containing things
    /// for the heroes to contend with/collect and interact with.
    /// </summary>
    internal sealed class EpicDungeon
    {
        #region Private Data Fields

        //Represents the rooms that make this dungeon up
        private List<Room> dungeonRooms = new List<Room>();

        /// <summary>
        /// Access to the Rooms in this Dungeon
        /// (to outside classes).
        /// </summary>
        internal List<Room> DungeonRooms
        {
            get
            {
                return dungeonRooms;
            }
            private set
            {
                dungeonRooms = value;
            }
        }

        #endregion Private Data Fields

        #region Constructors

        /// <summary>
        /// Constructor that allows a Dungeon to be created
        /// based on an array of Room or comma separated 
        /// Room objects (individual instances).
        /// </summary>
        /// <param name="newRooms">Rooms that populate this Dungeon with.</param>
        internal EpicDungeon(params Room[] newRooms)
            : this (newRooms.ToList())
        {

        }

        /// <summary>
        /// Constructor that populates this Dungeon with 
        /// the supplied List or Rooms.
        /// </summary>
        /// <param name="newRooms">A List of Rooms to populate this Dungeon with.</param>
        internal EpicDungeon(List<Room> newRooms)
        {
            if (newRooms != null && newRooms.Count > 0)
            {
                DungeonRooms = newRooms;    
            }
        }

        #endregion Constructors

        #region Internal Methods

        /// <summary>
        /// Internal method that allows a Room/Rooms to
        /// be added to this Dungeon.
        /// </summary>
        /// <param name="rooms">A single Room or an array of Rooms to add.</param>
        internal void AddDungeonRoom(params Room[] rooms)
        {
            if (rooms != null && rooms.Count() > 0)
            {
                foreach (Room room in rooms)
                {
                    DungeonRooms.Add(room);
                }
            }
        }

        /// <summary>
        /// Internal method that allows a Room/Rooms to
        /// be removed from this Dungeon.
        /// </summary>
        /// <param name="rooms">A single Room or an array of Rooms to remove.</param>
        internal void RemoveDungeonRoom(params Room[] rooms)
        {
            if (rooms != null && rooms.Count() > 0)
            {
                foreach (Room room in rooms)
                {
                    DungeonRooms.Remove(room);
                }
            }
        }

        #endregion Internal Methods

        #region Enumerator

        /// <summary>
        /// Enumerator that allows external classes
        /// to more easily iterate over the Rooms in this
        /// Dungeon (depending on a developers preferences).
        /// </summary>
        /// <returns>The DungeonRooms Enumerator.</returns>
        public List<Room>.Enumerator GetEnumerator()
        {
            return DungeonRooms.GetEnumerator();
        }

        #endregion Enumerator

        #region Internal Static Methods

        /// <summary>
        /// Internal static helper method that generates a List
        /// of Room objects (based on the seed values provided)
        /// and Room content.
        /// </summary>
        /// <param name="roomAmountSeed">A seed that helps determine the amount of Rooms.</param>
        /// <param name="roomContentSeed">A seed that helps determine the amount of Room Content (in each Room).</param>
        /// <returns>A List of fully populated Rooms based on the seeds specified.</returns>
        internal static List<Room> GenerateRandomRoomConfiguration(int roomAmountSeed = 5, int roomContentSeed = 3)
        {
            List<Room> dungeonRooms = new List<Room>();

            //Get a Room count based on the seed
            Random randomRoomCountObj = new Random();
            int thisGameRoomCount = randomRoomCountObj.Next(roomAmountSeed, (roomAmountSeed + 2));

            //Generate Rooms and add Random content
            for (int i = 0; i < thisGameRoomCount; i++)
            {
                dungeonRooms.Add(new Room(Room.GenerateRandomRoomContent(roomContentSeed)));
            }

            return dungeonRooms;
        }

        #endregion Internal Static Methods
    }
}

The key thing to note here is that Rooms support content and these content pieces can be any class that supports IRoomContent. Currently, our monsters support this interface so they can exist within Rooms. When a hero encounters a monster within a Room combat will be initiated. Combat based classes will support the ICombatant interface and, as an early conceptual piece, I’ve authored and tested the following method to get a feel for how combat may work between two ICombatant compatible objects. Here we are seeing dice and character classes in action.

/// <summary>
/// Private method that shows, in principle, how combat
/// can be handled between two ICombatant based objects.
/// </summary>
/// <param name="aggressor">The instigator of the combat represented by a class implementing ICombatant.</param>
/// <param name="target">The defender represented by a class implementing ICombatant.</param>
private void HandleCombat(ICombatant aggressor, ICombatant target)
{
    //Prepare values representing the dice roll capabilities (random) and values to keep a tally of the offence, defence and difference totals
    int damageTotal = 0, defenceTotal = 0, difference = 0;
    Random rollDie = new Random();

    //Roll attack dice for the aggressor and get a damage total
    aggressor.AttackDice.ForEach(attackDie =>
        {
            damageTotal += (byte)attackDie.DieFaces[rollDie.Next(0, 5)];
        });

    //Roll defence dice for the defender and get a defence total
    target.DefenceDice.ForEach(defenceDie =>
        {
            defenceTotal += (byte)defenceDie.DieFaces[rollDie.Next(0, 5)];
        });

    //Determine the difference between the damage/defence totals and deal damage to the target if required
    difference = damageTotal - defenceTotal;

    if (difference > 0)
    {
        target.Health -= difference;
    }
}

This has been somewhat of a massive mind dump of information, early concepts and basic implementations. In future posts I’ll be narrowing down my focus on each part of the application and implementing classes more fully as required. At the end of this week I’ll also be tallying up the votes for the ‘which monster to include in the game’ poll; so vote if you haven’t already.

Bye for now.

Merry Christmas

Firstly, for anyone following along, Merry Christmas all!

I’m only a handful of posts deep but I can honestly say that I’ve loved doing this. So much so that I, most likely, will plug a bit of money into this in the New Year and try to sort a custom domain/do a few customisations to the blog.

Currently, I’ve got a post in the pipeline looking at the WPF MediaElement control which I’ll try and have out sometime around the New Year; beer and parties permitting. After that, I want to throw in a little Objective C, Python and perhaps do a little more focused work surrounding Unity 3D (and do more game development in the New Year). As I’m eyeing up a few books in relation to create custom shaders in Unity and handling AI I think this should provide some interesting material to flesh out in the form of blog posts. In addition, I’ve got my hands on an Arduino experimentation kit and have had a Leap Motion controller for a while now (and I’d love to start getting into the API’s surrounding that).

I’ll grind out as much as I can manage before my brain explodes (and try to turn up to my wedding in the process).

In the meantime go eat and be merry, you’ve earned it!

Happy New Year to all.