Gigi Labs

Please follow Gigi Labs for the latest articles.
Showing posts with label lists. Show all posts
Showing posts with label lists. Show all posts

Wednesday, October 9, 2013

C# WPF: Control Panel using MVVM

Hi all! :)

In this article I'm going to show how you can implement a simple control panel in WPF using the MVVM design pattern. A control panel is a special case of a master/detail layout, where options are usually few and predefined, so you don't need to load any detail dynamically as options are selected.

This is an advanced article, so read on only if you have a fair grasp of the following: C#, WPF, data binding, and MVVM. I'm going to be using Visual Studio 2013 RC for the examples (just to try it out, really), but you should be able to use SharpDevelop or any version of Visual Studio from 2008 onwards.

Before we begin, a brief note on MVVM is in order. MVVM (Model-View-ViewModel) is an approach that promotes using data binding and commands over events. What we're going to do in this article can easily be done using the event-driven model (a la Windows Forms), but I'm writing this mainly for those who are trying to adopt the MVVM approach and who (like me) had a hard time grasping how it works.

So let's start off by adding a new C# WPF Application:


The New Project window above is an example of a master/detail layout. As you click on items in the treeview on the left (e.g. Windows or Web), the list of items in the middle changes accordingly. The treeview is a master view, while the area in the middle is the detail view.

For starters, in the XAML view, we can do away with the default <Grid> and set up our (not yet functional) master/detail layout as follows:

    <DockPanel>
        <ListBox Width="150" DockPanel.Dock="Left" />
        <ContentControl />
    </DockPanel>

Here's a screenshot of what it looks like in Visual Studio:


Isn't that simple? We use a ListBox for the master view, and move it to the left thanks to the DockPanel that contains it. The detail view is a ContentControl, which is a container we can use to hold user controls.

Next, we need a ViewModel for our MainWindow. Add a new class (right click on project, select Add -> New Item...) and call it MainVM. Make the class public, and set up some hardcoded values for the options that will appear in the master view:

    public class MainVM
    {
        private List<String> operations;

        public List<String> Operations
        {
            get
            {
                return this.operations;
            }
        }

        public MainVM()
        {
            this.operations = new List<String>() { "Add User", "List Users" };
        }
    }

In MainWindow's codebehind (i.e. MainWindow.xaml.cs), set the DataContext to an instance of MainVM in the constructor. This is important because when we do our data binding, the properties are always relative to the DataContext.

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            this.DataContext = new MainVM();
        }
    }

Back in our XAML view for MainWindow.xaml, we can now see that our binding works by adding an ItemsSource to the master ListBox:

<ListBox Width="150" DockPanel.Dock="Left" ItemsSource="{Binding Path=Operations}" />

Note how we're binding to the Operations property, and this is interpreted as belonging to the DataContext, which is a MainVM in this case. Sure enough, pressing F5 to debug the project shows that the ListBox is filled with the values we hardcoded earlier:


Right, now to actually fill in the detail view depending on what master option is selected. We'll first create each detail as a separate UserControl - this will allow us to easily plug them into our window.

Add your first UserControl (right click on project, Add -> New Item... and select "User Control (WPF)" - don't confuse it for the "User Control" which is actually a Windows Forms thing) and name it AddUserControl.xaml. Instead of implementing functionality to add or list users (which isn't the point of this article, we'll just stick some static content instead. Put this instead of the default grid:

    <StackPanel>
        <StackPanel Orientation="Horizontal">
            <TextBlock VerticalAlignment="Center">Name:</TextBlock>
            <TextBox Width="100" Margin="5 5 5 5" />
        </StackPanel>
    </StackPanel>

Create another UserControl, ListUsersControl.xaml, and replace the grid with the following:

    <StackPanel>
        <TextBlock>John Doe</TextBlock>
        <TextBlock>Mary Jane</TextBlock>
        <TextBlock>John Smith</TextBlock>
        <TextBlock>Chuck Norris</TextBlock>
    </StackPanel>

Now, we need to map each operation name (e.g. "Add User") to the corresponding UserControl. One option is to use a Tuple, but a better solution is to create a dedicated class. Add a new class named Operation and implement it like this:

    public class Operation
    {
        public String Name { get; set; }
        public UserControl Control { get; set; }

        public Operation(String name, UserControl control)
        {
            this.Name = name;
            this.Control = control;
        }
    }

You will also need to add the following near the top for UserControl to make sense:

using System.Windows.Controls;

Back in MainVM, replace the whole (String-based) class with the following (Operation-based):

    public class MainVM
    {
        private List<Operation> operations;

        public List<Operation> Operations
        {
            get
            {
                return this.operations;
            }
        }

        public MainVM()
        {
            this.operations = new List<Operation>();
            this.operations.Add(new Operation("Add User", new AddUserControl()));
            this.operations.Add(new Operation("List Users", new ListUsersControl()));
        }
    }

All we have left to do is wire up the bindings on the XAML view of MainWindow.xaml. First, we need to change our ListBox as follows:

        <ListBox Name="MasterView" Width="150" DockPanel.Dock="Left"
                 ItemsSource="{Binding Path=Operations}" DisplayMemberPath="Name" />

I've added two things here. First, I added a name to the ListBox so that I can refer to it from my ContentControl. I also added a DisplayMemberPath. This tells the ListBox that for each Operation item, it needs to show the Name property. If you leave that out, it will just display Operation.ToString() by default.

Next, we bind our ContentControl's Content property as follows:

        <ContentControl Content="{Binding ElementName=MasterView, Path=SelectedItem.Control}" />

The binding refers to the control named MasterView (i.e. our ListBox), and we hook it up with the ListBox's SelectedItem property. Since the SelectedItem is actually an Operation, we get the UserControl associated with that Operation (via the Control property). Setting the Path to SelectedItem.Control does the trick.

That's it! Press F5 to test the application. When you click on "Add User", you get the correct UserControl:


...and clicking on "List Users" works just as well:


Woohoo! :) We managed to implement an MVVM master/detail control panel with just three lines of XAML (two controls, really) and some data binding magic.

As you have seen, the particular nature of a control panel makes an MVVM implementation particularly easy, because each detail view can reside in memory. This does not apply to all master/detail layouts though: if the master list is really long, it may be a better idea to load detail views lazily on demand. That could be the topic for a future article. Stay tuned! :)

Sunday, October 6, 2013

C#: Extracting Zipped Files with SharpZipLib

Hello there! :)

In this article, we're going to learn how to extract files from a .zip file using a library called SharpZipLib.
Additionally, we will also learn how to work with third-party libraries with functionality we might not get by default. This is because SharpZipLib is not part of the .NET Framework, and is developed by an independent team.

To get started, we need to create a new Console Application in SharpDevelop (or Visual Studio, if you prefer), and also download SharpZipLib from its website. When you extract the contents of the .zip file you downloaded, you'll find different versions of ICSharpCode.SharpZipLib.dll for different .NET versions. That's the library that will allow us to work with .zip files, and we need the one in the net-20 folder (the SharpZipLib download page says that's the one for .NET 4.0, which this article is based on).

Now, to use ICSharpCode.SharpZipLib.dll, we need to add a reference to it from our project. We've done this before in my article "C#: Unit Testing with SharpDevelop and NUnit". You need to right click on the project and select "Add Reference":


In the window that comes up, select the tab called ".NET Assembly Browser", since we want to reference a third party .dll file. Open the ICSharpCode.SharpZipLib.dll file, click the "OK" button in the "Add Reference" dialog, and you're ready to use SharpZipLib.


In fact, you will now see it listed among the project's references in the Projects window (on the right in the screenshot below):


Great, now how do we use it?

This is where our old friend, Intellisense, comes in. You might recall how we used it to discover things you can do with strings in one of my earliest articles here, "C# Basics: Working with Strings". This applies equally well here: as you begin to type your using statement to import the functionality you need from the library, Intellisense suggests the namespace for you:


Now SharpZipLib has a lot of functionality that allows us to work with .zip files, .tar.gz files and more. In our case we just want to experiment with .zip files, so we're fine with the following:

using ICSharpCode.SharpZipLib.Zip;

That thing is called a namespace: it contains a set of classes. If you type it into your Main() method and type in a dot (.) after it, you'll get a list of classes in it:


A namespace is used to categorise a set of related classes so that they can't be confused with other classes with the same name. Java's Vector class (a kind of resizable array) is a typical example. If you create your own Vector class to represent a mathematical vector, then you might run into a naming conflict. However, since the Java Vector is actually in the java.util namespace, then its full name is actually java.util.Vector.

This works the same way in C#. The List class you've been using all along is called is actually called System.Collections.Generic.List. We usually don't want to have to write all that, which is why we put in a using statement at the top with the namespace.

When we're working with a new namespace, however, typing the full name and using Intellisense allows us to discover what that namespace contains, without the need to look at documentation. In the screenshot above, we can already guess that ZipFile is probably the class we need to work with .zip files.

Intellisense also helps us when working with methods, constructors and properties:


I suppose you get the idea by now. Let's finally actually get something working. To try this out, I'm going to create a zip file with the following structure:

+ test1.txt
+ folder
    + test2.txt
    + test3.txt

I've used WinRAR to create the zip file, but you can use anything you like. I named it "zipfile.zip" and put it in C:\ (you might need administrator privileges to put it there... otherwise put it wherever you like). Now, we can easily obtain a list of files and folders in the .zip file with the following code:

        public static void Main(string[] args)
        {
            using (ZipFile zipFile = new ZipFile(@"C:\\zipfile.zip"))
            {
                foreach (ZipEntry entry in zipFile)
                {
                    Console.WriteLine(entry.Name);
                }
            }
         
            Console.ReadLine();
        }

This gives us:


We use the using keyword to close the .zip file once we're done - something we've been doing since my article "C#: Working with Streams". You realise you need this whenever you see either a Dispose() or a Close() method in Intellisense. We are also using looping over the zipFile itself - you realise you can do a foreach when you see a GetEnumerator() method in Intellisense. Each iteration over the zipFile gives us a ZipEntry instance, which contains information about each item in the .zip file. As you can see in the output above, entries comprise not just files, but also folders.

Since we want to extract files, folders are of no interest for us. We can use the IsFile property to deal only with files:

                    if (entry.IsFile)
                        Console.WriteLine(entry.Name);

In order to extract the files, I'm going to change the code as follows:

        public static void Main(string[] args)
        {
            using (ZipFile zipFile = new ZipFile(@"C:\\zipfile.zip"))
            {
                foreach (ZipEntry entry in zipFile)
                {
                    if (entry.IsFile)
                    {
                        Console.WriteLine("Extracting {0}", entry.Name);
                 
                        Stream stream = zipFile.GetInputStream(entry);
                        using (StreamReader reader = new StreamReader(stream))
                        {
                            String filename = entry.Name;
                            if (filename.Contains("/"))
                                filename = Path.GetFileName(filename);
                             
                            using (StreamWriter writer = File.CreateText(filename))
                            {
                                writer.Write(reader.ReadToEnd());
                            }
                        }
                    }
                }
            }
         
            Console.ReadLine();
        }

Note that I also added the following to work with File and Path:

using System.IO;

Extracting files involves a bit of work with streams. The zipFile's GetInputStream() method gives you a stream for a particular entry (file in the .zip file), which you can then read with a StreamReader as if you're reading a normal file.

I added a bit of code to handle cases when files are in folders in the .zip file - I am finding them by looking for the "/" directory separator in the entry name, and then extracting only the filename using Path.GetFileName(). [In practice you might have files with the same name in different folders, so you'd need to actually recreate the folders and put the files in the right folders, but I'm trying to keep things simple here.]

Finally, we read the contents of the entry using reader.ReadToEnd(), and write it to an appropriately named text file. If you run this program and go to your project's bin\Debug folder in Windows Explorer, you should see the test1.txt, test2.txt and test3.txt files with their proper contents. [Again, the proper way to deal with streams is to read chunks into a buffer and then write the file from it, but I'm using reader.ReadToEnd() for the sake of simplicity.]

Excellent! In this article, we have learned to list and extract files from a .zip file. We also learned why namespaces are important. But most importantly, we have looked at how to reference third party .dlls and discover how to use them based only on hints from Intellisense and our own experience. In fact, the above code was written without consulting any documentation whatsoever, solely by observing the intellisense for SharpZipLib. While it is usually easier to just find an example on the internet (possibly in some documentation), you'll find that this is a great skill to have when documentation is not readily available.

If you found this interesting, be sure to check back for future articles in which I will be covering other useful topics! Also, if you happen to like computer games, be sure to check out GOG's catalogue of cheap, DRM-free games. If you buy games through this link, you will be supporting Programmer's Ranch at the same time.

Sunday, September 22, 2013

C#: Mocking and Dependency Injection for Unit Testing a File Sorting Program

Hullo folks! :)

In yesterday's article, "C#: Unit Testing with SharpDevelop and NUnit", we learned about unit tests: what they are, why we use them, and how we write and execute them. The article ended with a number of insights about them. One of these insights was that it is not easy to write unit tests for code that relies on databases, the network, or other external resources.

In today's article, we're going to address this problem by learning about mocking and dependency injection. These might sound like big buzz-words, but you'll see in this article that they're really nothing special. To see this in action, we'll write a small program that loads a file from the hard disk and sorts it alphabetically, line by line.

This article is a bit on the advanced side, so ideally you should know your OOP and also be familiar with basic unit testing (e.g. from yesterday's article) before reading it.

Start off by creating a new Console Application in SharpDevelop. When this is done, add a new class (right click on project in Projects window, Add -> New Item...) and name it Sorter. At the top, add the following to allow us to read files and use lists:

using System.Collections.Generic;
using System.IO;

Next, add a member variable in which we can store the lines in the file:

private String[] lines;

Add a constructor in Sorter that takes the name of the file to sort, and loads it into the variable we just declared:

        public Sorter(String filename)
        {
            this.lines = File.ReadAllLines(filename);
        }

Now, add a method that actually does the sorting:

        public String[] GetSortedLines()
        {
            List<String> sortedLines = new List<String>(lines);
            sortedLines.Sort();
            return sortedLines.ToArray();
        }

This way of sorting is not the only one and not necessarily the best, but I chose it because it's simple and doesn't change the lines variable, just in case you want to keep it in its original unsorted format for whatever reason.

Let's try and write a test for this code. Add a new class called SorterTest (as I've already mentioned in yesterday's article, people usually put tests into their own project, but I'm trying to teach one concept at a time here). After adding a reference to nunit.framework.dll (check yesterday's article in case you're lost), set up the SorterTest.cs file as follows:

        [Test]
        public void GetSortedLinesTest()
        {
            Sorter sorter = new Sorter("test.txt");
            String[] s = sorter.GetSortedLines();
          
            Assert.AreEqual("Gates, Bill", s[0]);
            Assert.AreEqual("Norris, Chuck", s[1]);
            Assert.AreEqual("Torvalds, Linus", s[2]);
            Assert.AreEqual("Zuckerberg, Mark", s[3]);
        }

Create a file in your bin\Debug folder called test.txt and put the following in it:

Zuckerberg, Mark
Norris, Chuck
Gates, Bill
Torvalds, Linus

Open the Unit Tests window in SharpDevelop (View -> Tools -> Unit Tests) and run it. You can see that the test passes.

Great.

Actually, this is the wrong way of writing unit tests for this kind of thing. We have a dependency on the filesystem. What would happen if that file suddenly disappears? As a matter of fact, we are supposed to be testing the sorting logic, not whether the file is available or not.

In order to do this properly, we're going to have to refactor our code. We need to take our file loading code out of there. Create a new class called FileLoader and add the following at the top:

using System.IO;

...and then set up FileLoader as follows:

    public class FileLoader
    {
        private String[] lines;
      
        public String[] Lines
        {
            get
            {
                return this.lines;
            }
        }
      
        public FileLoader(String filename)
        {
            this.lines = File.ReadAllLines(filename);
        }
    }

In Sorter, remove the constructor as well as the using System.IO; and the lines variable. Instead, we'll pass our FileLoader as a parameter:

        public String[] GetSortedLines(FileLoader loader)
        {
            List<String> sortedLines = new List<String>(loader.Lines);
            sortedLines.Sort();
            return sortedLines.ToArray();
        }

This is called dependency injection: instead of creating the dependency (in our case a file) from within the Sorter class, we pass it as a parameter. This allows us to substitute the dependency for a fake (known as a mock). To do this, we'll need to take advantage of polymorphism (see "C# OOP: Abstract classes, fruit, and polymorphism". Create an interface (when adding a new item, instead of Class, specify Interface) and name it IFileLoader:


An interface is a form of abstract class - it cannot be instantiated, and it declares methods and/or properties that don't have any implementation because they should be implemented by the classes that inherit from (or implement) that interface. In an interface, however, no methods/properties have an implementation. It is used as a contract, saying that any class implementing the interface must implement its methods/properties. In our case, IFileLoader will be this:

    public interface IFileLoader
    {
        String[] Lines
        {
            get;
        }
    }

We then specify that FileLoader implements IFileLoader; this is the same as saying that FileLoader inherits from IFileLoader:

public class FileLoader : IFileLoader

FileLoader already has the necessary Lines property, so we're fine. Next, we replace the FileLoader parameter in Sorter.GetSortedLines() with an instance of the interface:

public String[] GetSortedLines(IFileLoader loader)

This allows us to pass, as a parameter, any class that implements IFileLoader. So we can create a class, MockFileLoader, that provides a hardcoded list of names:

    public class MockFileLoader : IFileLoader
    {
        private String[] lines = { "Zuckerberg, Mark", "Norris, Chuck", "Gates, Bill", "Torvalds, Linus" };
      
        public String[] Lines
        {
            get
            {
                return this.lines;
            }
        }
    }

We can now rewrite our unit test like this:

        [Test]
        public void GetSortedLinesTest()
        {
            IFileLoader loader = new MockFileLoader();
            Sorter sorter = new Sorter();
            String[] s = sorter.GetSortedLines(loader);
          
            Assert.AreEqual("Gates, Bill", s[0]);
            Assert.AreEqual("Norris, Chuck", s[1]);
            Assert.AreEqual("Torvalds, Linus", s[2]);
            Assert.AreEqual("Zuckerberg, Mark", s[3]);
        }

If you run the unit test, you'll find that it works just like before, just that this time our unit test isn't dependent on any file and can run just file without one:


In this article, we have seen how to create mock classes that emulate the functionality of our normal classes, but can replace them in unit tests when dependencies exist. To facilitate this, both the mock class and the normal class implement a common interface, and an instance of this interface is passed as a parameter to the method being tested. This is called dependency injection and allows us to control what is being passed to the method.

It is not always easy to write mocks. First, as this article has shown, code may need to be refactored in order to isolate dependencies and support dependency injection. Secondly, mocking complex classes (e.g. an IMAP server) can take a great deal of effort and might not necessarily be worth it. Use your own judgement to decide whether you need unit tests in such situations.

Thanks for reading, and be sure to visit here often to read more articles that might be useful.

Friday, August 9, 2013

C# OOP: Encapsulation and Properties

Hi everyone!

Some recent articles have discussed different aspects of Object Oriented Programming. Today we'll talk about controlling access to members (variables or methods) of our classes.

Let's begin with a scenario. We have an accounting program that keeps track of a person's money. First, we need to use the following library:

using System.Collections.Generic;

Then we declare a Transaction class to contain the details of each transaction (deposits, withdrawals... basically anything that affects the amount of money in the account):

    class Transaction
    {
        public DateTime date;
        public String detail;
        public float amount;
       
        public Transaction(DateTime date, String detail, float amount)
        {
            this.date = date;
            this.detail = detail;
            this.amount = amount;
        }
    }

We also need an Account class to keep the overall account information, as well as a list of all the transactions in the account:

    class Account
    {
        public String name;
        public float balance;
        public List<Transaction> transactions;
       
        public Account(String name)
        {
            this.name = name;
            this.balance = 0.0f;
            this.transactions = new List<Transaction>();
        }
       
        public void Show()
        {
            Console.WriteLine("Account for {0}", name);
            Console.WriteLine();
           
            foreach (Transaction transaction in transactions)
            {
                Console.WriteLine("{0:yyyy-MM-dd}  {1, -30}  {2}",
                        transaction.date, transaction.detail, transaction.amount.ToString("0.00").PadLeft(8, ' '));
            }
           
            Console.WriteLine();
            Console.WriteLine("Balance: {0:0.00}", this.balance);
        }
    }

We can now see how this works with some sample code in Main():

            Console.Title = "C# Encapsulation with Accounting";
           
            Transaction trans1 = new Transaction(new DateTime(2013, 08, 07), "Deposit: My first salary", 20.0f);
            Transaction trans2 = new Transaction(new DateTime(2013, 08, 08), "Withdrawal... need cash", -15.0f);
            Transaction trans3 = new Transaction(new DateTime(2013, 08, 09), "Deposit: Birthday present", 10.0f);
           
            Account account = new Account("Bill Gates");
           
            account.transactions.Add(trans1);
            account.balance += trans1.amount;
            account.transactions.Add(trans2);
            account.balance += trans2.amount;
            account.transactions.Add(trans3);
            account.balance += trans3.amount;

            account.Show();
           
            Console.ReadKey(true);

So here we've created an account for Bill Gates and added three transactions. The Show() method gives us a picture of the account status and history:


That's great. But what if the guy writing the code in Main() forgets to update the account balance? The sum of the transactions won't agree with the value in the balance member variable. We could provide a method to take care of this in Account:

        public void AddTransaction(Transaction transaction)
        {
            transactions.Add(transaction);
            this.balance += transaction.amount;
        }

...and while this is certainly useful, it doesn't really solve the problem. Because while a programmer might use this method, there is nothing to keep him from updating transactions and balance separately, the old way, as illustrated earlier. Even worse, someone might actually tamper with them, potentially removing transactions or modifying the balance into something different.

The one thing we've been doing wrong all along is declaring all member variables and methods in our classes as public. When they're public, it means anyone can touch them. We can restrict access to members by using a protected or private access modifier instead of public (there are others, but they're not important at this stage).

Once we switch the member variables in the Account class to private:

        private String name;
        private float balance;
        private List<Transaction> transactions;

...then the program won't compile:


That's because we're accessing these private member variables directly from within Main(). When a variable is private, it means that only code within the same class can access it. So it's ok for the AddTransaction() method we added earlier to use the transactions member variable, but the code in Main() can't. Instead, the code in Main() must be refactored to use AddTransaction():

            account.AddTransaction(trans1);
            account.AddTransaction(trans2);
            account.AddTransaction(trans3);

With this change, it compiles just as well. So we've just seen how we can prevent users of a class from tampering with its internal state, and yet still do useful stuff with it via the methods it does expose as public. This is called encapsulation, and it effectively means "data hiding". In OOP it is usually the case that our classes provide a public interface by which other objects can use them, but they hide all the rest from public view.

Naturally, it is often the case that other objects want to access member variables for legitimate reasons. In that case, instead of making the member variable public, we add methods allowing access to them:

        public String GetName()
        {
            return this.name;
        }
       
        public void SetName(String value)
        {
            this.name = value;
        }
       
        public float GetBalance()
        {
            return this.balance;
        }

These are called getter and setter methods, because they allow you to retrieve and modify the variable. A setter can be omitted (as with the balance variable) if that variable is meant to be read-only.

Although using getter and setter methods is a great way of using encapsulation in any OOP language, C# provides the use of properties, which do the same thing but are arguably more elegant:

        public String Name
        {
            get
            {
                return this.name;
            }
            set
            {
                this.name = value;
            }
        }
       
        public float Balance
        {
            get
            {
                return this.balance;
            }
        }

Properties are actually converted to getter and setter methods during compilation, but this process is transparent to you (the programmer). Using them in code is pretty easy:

Console.WriteLine("{0} has {1} Euros in his account.", account.Name, account.Balance);

Right, so what about the protected access modifier? It's like private, but also allows subclasses to access a class's members. You should use it sparingly, or not at all. Scott Meyers explains why in his excellent book "Effective C++: 55 Specific Ways to Improve Your Programs and Designs". When you make something public, there are potentially infinitely many places from where it can be accessed and modified. So if you decide to change that variable (e.g. remove it and replace it with a computation), you have to refactor all those places. If something is protected, it can be accessed from any subclass, so there are still porentially infinitely many places from where it can be modified. If you want a subclass to access a variable, your best bet is to encapsulate it using a getter/setter pair or a property, and have the subclass access that.

To see this idea in action, let's remove the Account class's balance variable and replace it with a sum of the transaction amounts:

         public float Balance
        {
            get
            {
                float bal = 0.0f;
               
                foreach (Transaction transaction in this.transactions)
                {
                    bal += transaction.amount;
                }
               
                return bal;
            }
        }

So like this, any other classes accessing the Balance property may continue to do so without needing to refactor anything. In our case we only need to make some small changes in the Account class itself (no need to maintain a separate balance variable any more in the constructor and in AddTransaction(), and use the property instead of the variable in Show()). But if we had to refactor a hundred other classes to remove the balance variable, it would have been a very expensive change.

Cool. So in this article we learned why we should hide certain internal class data from outside code that might tamper with it - a practice called encapsulation. Encapsulation is so important that, together with inheritance and polymorphism, it is known as one of the Three Pillars of OOP. We also learned about access modifiers (public, protected, private), getter/setter methods, as well as properties - something unique to C#.

From these OOP articles you might begin to see what OOP is really about: the complex relationships between objects make designing OOP software quite a challenge. It's also quite fun. :)

I hope you enjoyed this article, and check back for more! :)

Saturday, July 20, 2013

C# OOP: Queues and Stacks with Inheritance

Hi everyone! :)

In yesterday's article ("C# OOP: Creating a List using Composition") we used classes to create a List data structure. Today we're going to create a queue and a stack using the same principle.


The above diagram shows what a queue looks like in theory. (When I first drew this diagram, I made the mistake of putting the orange labels at the bottom. If you think about it for a minute, you'll realise why it's a horribly wrong thing to do.) There are a number of people in the queue, and they all get served one by one by the dude at the desk. Unless you're in Malta, the guy at the back typically doesn't get served before the guy at the front.

A queue is pretty much a special kind of list. It has the internal structure of a list, but supports two operations: Enqueue and Dequeue. Enqueue means adding an item to the end of the queue, while Dequeue means removing the item at the front of the queue and doing something with it.

We can start off with yesterday's code for the List:

    class ListItem
    {
        public ListItem Next;
        public String Data;
       
        public ListItem(String data)
        {
            this.Next = null;
            this.Data = data;
        }
    }
   
    class List
    {
        public ListItem Head;
        public ListItem Tail;
       
        public List()
        {
            this.Head = null;
            this.Tail = null;
        }
       
        public void Add(String data)
        {
            ListItem item = new ListItem(data);
           
            if (this.Head == null) // list is empty
            {
                this.Head = item;
                this.Tail = item;
            }
            else
            {
                // set (old) tail's Next to new item
                this.Tail.Next = item;
                // new item is the new tail
                this.Tail = item;
            }
        }
    }

Since a queue is so similar to a list, there isn't much point in simply rewriting lots of code to create the queue. As much as possible, we should reuse code. This is called the Don't Repeat Yourself (DRY) principle.

Let's start the queue based on this code:

    class Queue : List
    {
       
    }

This means that Queue is a List. This is just like saying Dog is a mammal: the dog inherits the characteristics of a mammal (it has fur, doesn't lay eggs, etc) and perhaps adds some particular characteristics of its own (barks, wags tail, drools, etc). In OOP, this actually means that the Queue inherits the data members and methods of the List. So in our Main() method, we can already use the Queue as if it were a List:

        public static void Main(string[] args)
        {
            Console.Title = "C# OOP Inheritance";
           
            Queue queue = new Queue();
            queue.Add("Bill Clinton");
            Console.WriteLine(queue.Head.Data);
           
            Console.ReadLine();
        }

In Queue, we can add the Enqueue() and Dequeue() methods that are queue-specific and don't belong in the List:

    class Queue : List
    {
        public void Enqueue(String data)
        {
            this.Add(data);
        }
       
        public String Dequeue()
        {
            if (this.Head == null)
            {
                return null;
            }
            else
            {
                // keep reference to the first guy in the queue
                String oldHead = this.Head.Data;
               
                // set head to the second guy in the queue
                this.Head = this.Head.Next;
               
                // return the guy who was first, for consumption
                return oldHead;
            }
        }
    }

For Enqueue(), we use the Add() method inherited from List, since it adds items to the end of the list and is enough to achieve what we need for Enqueue(). In Dequeue(), we return the first item in the queue, and the second item takes its place.

In Main(), we can try this out:

            Queue queue = new Queue();
            queue.Enqueue("Bill Clinton");
            queue.Enqueue("Paris Hilton");
            queue.Enqueue("Chuck Norris");
           
            String item = String.Empty;
            while (item != null)
            {
                item = queue.Dequeue();
                Console.WriteLine(item);
            }
           
            Console.ReadLine();

...and the result is...


That's great, but the extent of reusability of the List doesn't end here. Let's also create a Stack.


A stack is just what the name suggests: a bunch of things on top of each other. Books and Pringles make really good examples of stacks. You add things to the top of the stack, and remove them from the top. You can't remove items from the bottom of a stack without making a mess.

The stack supports two operations: Push (add item to top of stack) and Pop (remove item from top of stack - think Pringles). Again, we can inherit from the List and implement this particular functionality:

    class Stack : List
    {
        public void Push(String data)
        {
            this.Add(data);
        }
       
        public String Pop()
        {
            String data = null;
           
            if (this.Head == null) // stack is empty
            {
                data = null;
            }
            else if (this.Head.Next == null) // stack has just one item
            {
                data = this.Head.Data;
                this.Head = null;
                this.Tail = null;
            }
            else // stack has at least two items
            {
                ListItem currentItem = this.Head;
               
                while (currentItem.Next != this.Tail)
                    currentItem = currentItem.Next;
               
                data = this.Tail.Data;
                currentItem.Next = null;
                this.Tail = currentItem;
            }
           
            return data;
        }
    }

Uhhh... Pop() is a little more complicated than Dequeue() because we need to first navigate to the item before the tail, and we have to do that from the head since the Tail doesn't have any backwards pointers. We could make this more efficient by using a doubly linked list instead, but that's beside the point.

We can now test the Stack:

            Stack stack = new Stack();
            stack.Add("One");
            stack.Add("Two");
            stack.Add("Three");
            stack.Add("Four");
           
            String item = String.Empty;
            while (item != null)
            {
                item = stack.Pop();
                Console.WriteLine(item);
            }
           
            Console.ReadLine();

...which results in...


You'll notice that the output is in reverse order compared to how we added the items. That's because a stack is a Last In First Out (LIFO) data structure, while a queue is First In First Out (FIFO).

Fantastic. In this article we used inheritance to reuse functionality in the List and write specialised code for Queues and Stacks without duplicating code. Effectively we ended up with the following inheritance tree:


Queue and Stack are both Lists in the same way that Dogs and Cats are both Mammals. A better way of saying this is that Queue and Stack extend List (in fact Java uses the extends keyword instead of the colon operator used by C# and C++).

It is also important to know that in C#, all classes implicitly extend the Object class, which provides some methods such as ToString() and GetHashCode() to all classes. We'll learn more about these in the coming articles.

That's all for today... come back for the next article! :)