Perl – Labels make your code look even more beautiful

Just some fun code, because I keep on being amazed about how effective, straight forward and especially beautiful Perl can be!

#!/usr/bin/perl -w

use warnings;
use strict;

QUESTION:{

    print 'Type any text, enter "q" to quit: ';
    chomp (my $input = <STDIN>);

    last if ($input eq "q");

    my @arry = split //, $input;
    print "Reversed: ". join("",reverse @arry)."\n";
    redo;
}

print "Bye!\n";

 

C# Blog – Use an Extention Method to Convert a Boolean to Yes or No

There are many ways to convert a boolean to text. The most simple one is by using the .ToString() method.

Let’s look at the following code:

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            bool answer;

            answer = (DateTime.Now.Year == 2016);

            
            Console.WriteLine("Yes or no: the current year is 2016?");
            Console.WriteLine("The answer is: {0}", answer.ToString());

            Console.ReadLine();
        }

     }
}

The output will be “The answer is: true” (or false). That’s not what you want, you want the answer to be Yes or No.

You could try something like this:

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            bool answer;

            answer = (DateTime.Now.Year == 2016);

            
            Console.WriteLine("Yes or no: the current year is 2016?");
            Console.WriteLine("The answer is: {0}", answer ? "Yes" : "No");

            Console.ReadLine();
        }

      

    }

  }

And that works just fine. However, what if you have multiple places where you want to convert a boolean to “Yes” or “No”? You would have to write that code everytime you do the conversion.

And what if you have added this 100 times, and decide afterwards that you do not want “Yes” and “No”, but “Yeah!” and “Nope…”?

For that, the most practical way is using an extention method.

By doing so, you can add functionality to a boolean (and it works on other types as well, in fact, it works on all types!). This is how that’s done:

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            bool answer;
            answer = (DateTime.Now.Year == 2016);
            
            Console.WriteLine("Yes or no: the current year is 2016?");
            Console.WriteLine("The answer is: {0}", answer.ToYesNo());

            Console.ReadLine();
        }
   }

    public static class Extentions
    {
        public static string ToYesNo(this bool b)
        {
            return (b ? "Yes" : "No");
        }
    }
}

All you have to do is add a top-level static class to your project (it can be placed in a separate file, or added to other code, you only need to add it once in your project. The name of that class can be anything, but it makes more sense if you give it a logical name, like “Extentions”.

In that class, you put a public static method, with the return type of your choice (a string in this case). The trick is that you give that method a parameter with the prefix “this“, followed by the type you want to extend (a bool in this case). Give the parameter a name (b).

In the example above, the type bool has a new method: .ToYesNo(). When calling the method, omit the parameter. Simple and effective!

Imagine what you can do with that! Just for fun:

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string sum = "10+10";
            
            Console.WriteLine("The outcome of {0} is {1}",sum, sum.CalcSum());

            Console.ReadLine();
        }
   }

    public static class Extentions
    {
        public static int CalcSum(this string s)
        {
            int ret = 0;
            string[] p = s.Split('+');
            ret = int.Parse(p[0]) + int.Parse(p[1]);

            return ret;
        }
    }
}

Enjoy!

 

 

C# Blog – Exam 70-483 – Programming in C#

 

The day before yesterday I passed the 70-483 exam, which makes me a Microsoft Specialist 🙂 .

Of course I had a giant party afterwards … well, no. I fell asleep on the couch and slept for about 24 hours. And actually even today my brains are wondering what happened there in that exam room.

This was not my first exam, in fact it was number eight. Those other exams however were long ago. In 2004 I certified as MCAD, in 2008 as MCSA. What I can tell from this experience is that – in my opinion – Microsoft has made the exams more difficult. More focus on insights and more focus on deeper knowledge.

The first exam question immediately made me wonder how I’d ever survive until the end of the exam. Below I’ll describe how I prepared for the exam, and.. well, let me put it this way, that preparation only covered about 10 percentage of the exam questions.

My next exam will be the 70-484. From the 70-483 exam I learned something about how to prepare. I might as well share that in this blog.

For the 70-483 I used the following resources:

  • MOC On-Demand 20483: Programming in C#: 15 hours of video tutorials
  • The official book that comes with that Online course: 20483B – Programming in C#
  • Book: Exam Ref 70-483 – Programming in C#
  • Test exams from Measure-up

Next to that I’ve spend quite some hours in Visual Studio, trying and testing. The Exam Ref book contained many explanations that gave me new insights, I applied those insights in my running projects immediately.

But what helpend me passing the exam was my years of experience as developer.

So, what should I do for the 70-484 exam? I am new to WinRT. I’ve never actually built a Windows Store App. I’ve planned the following:

  • Book:  Windows 8.1 Apps wit XAML and C# – unleashed
  • Book: Exam Ref 70-484 – Essentiële of Developing Windows Store Apps Using C#
  • No MOC On-Demand, for the simple reason that it does not exists for this exam.
  • Probably the most important, as learned trom the 70-483 exam: I am going to inspect every URL I find in the before mentioned books. Often the authors write something like “For more information about XXXX visit www.Microsoft.com/xxxxxetc.” This is not just for people that are curious, those links contain essential info, which will come back in the exam (or well, I think. It is the case for 70-483).

C# Blog – Do Not Panic! Implement IComparable To Customize Sorting a Generic List

Do Not Panic!

If you are just starting with C# this title may scare you. Well, the terminology did scare me when I just started. However, when you look at it, those <T>’s and I’s are there to make things more easy.

What does it mean? Let’s look at that with an example.

Image you build a class called “Dummy”. This class has some properties, e.g. a Name, an Email and an Info (all strings). You have five dummies, and want to store them in a list.

List<T>

That is where you use a generic list. You use the build in List<T>, where the T means “just give me a Type, and the list will contain entries of that type only”. Your class Dummy is a Type, so you can make a List of Type Dummy. In syntax: List<Dummy>.

You add your five duimies to that list (as shown in the source code below).

The .Net framework doesn’t know anything about your dummies. Yes, it has a definition, but it does not know the exact meaning of it … in the end the .Net framework exists in a landscape of 0’s and 1’s, if you want something to happen correctly, you’ll have to tell how to do that.

System.InvalidOperationException

Imagine you want to sort your newly created list of dummies. The build-in List<T> (the one that you made a List <Dummy>) does have a sort method. If you call that method, you’ll get an System.InvalidOperationException. You told the list to sort, but you did not tell it how to do that. Sort on Name, Email, Info? And if you sort on let’s say Info, do you want it to be sorted alphabetical, or maybe some other way? The point is that the list must know how to sort. If only the Dummy class contained some infromation about that…

Interfaces: IComparable<T>

That’s where interfaces come in. If you implement an interface in a class, things like a List still don’t know anything about the meaning of your class, but they do know that there is some functionality in the class they can handle: the information provided by the interface.

When sorting, the List<T> looks for a method that tells how to sort. That method has a signature that is defined in the interface IComparable<T>.

Implementing IComparable<T> in your class means something like: This class has a method that is defined in IComparable. The type that is handled by that method is a generic, in other words, tell me the type, and I’ll respect that type when handling the method!

In our case we want that method to handle a Dummy. So what do we do? In our Dummy Class we implement the interface IComparable of type Dummy. In syntax: IComparable<Dummy>.

If we do so, the List knows how to sort: in your class it looks for the method that belongs to IComparable, and that method is going to tell the List how to sort.

How to sort?

How does that method tell how to sort? Well… it doesn’t by itself, you’ll have to put some code in that method for that. The method looks like this:

public int CompareTo(Dummy other)

As you can see, it returns an int, and it expects a Dummy. This is how it works. When you have an instance of Dummy, that instance also has this method. The method can be called passing another Dummy.

In your code you decide if the other Dummy should be placed before or after the current Dummy when sorting.

If the other Dummy should be placed before the current one, return 1. If the other Dummy should be placed after the current one, return -1.

This gives the List enough information to apply sorting.

Based on what do you return -1 or 1? Well, that’s up to you!

Code Example

In the following code example, a Dummy class is created, the IComparable<T> is implemented, and the sorting will be based on the number of characters in the “Info” property.

You can download the sourcecode from github

Start a new C# WPF project. Call it “Sorter”

In MainWindow.xaml replace the xaml with the following:

<Window x:Class="Sorting.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Sorting"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <DataGrid x:Name="dataGrid" HorizontalAlignment="Left" Margin="17,16,0,0" VerticalAlignment="Top" Height="293" Width="490"/>
    </Grid>
</Window>

In MainWindow.xaml.cs place the following code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace Sorting
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {

        class Dummy : IComparable<Dummy>
        {

            public string Name { get; set; }
            public string Email { get; set; }
            public string Info { get; set; }

            public int CompareTo(Dummy other)
            {
                return (Info.Length > other.Info.Length ? -1 : 1);
             }
        }

        public MainWindow()
        {
            InitializeComponent();

            fillGrid();
        }

        void fillGrid()
        {

            List<Dummy> lst = new List<Dummy>();

            lst.Add(new Dummy() { Name = "Joe", Email = "joe@somedomain.com", Info = "Member of the cocker spaniel club." });
            lst.Add(new Dummy() { Name = "Adrian", Email = "adrian@somedomain.com", Info = "Used to be acrobat" });
            lst.Add(new Dummy() { Name = "Bassie", Email = "bassie@somedomain.com", Info = "His brother used to be a super-hero acrobat, now a days he sells cars." });
            lst.Add(new Dummy() { Name = "Mary", Email = "mary@somedomain.com", Info = "Sweet Mary, I'm coming home!" });
            lst.Add(new Dummy() { Name = "Roger", Email = "roger@somedomain.com", Info = "Likes swimmming in water." });

            lst.Sort();

            dataGrid.ItemsSource = lst;

        }
    }
}

Hopefully, next time you see text with a lot of <T>, capital I’s and Generics, you’ll think: Awesome, someone has spent a lot of time to make my live easier!

 

 

C# Blog – Ready, Set, Go! Using a Stopwatch and Tracing to find bottlenecks in your app

So every now and then you find things that you wish you’d found many years ago. For me, one of those things is the System.Diagnostics.Stopwatch. It is propably one of the simplest objects you can think of, but it saves you a lot of time. It does what you’d expect: it measures time. And you no longer have to write code to measure time yourself.

In this post I’ll give an example of using the stopwatch to measure the time that it takes to run a heavy method. The fact that the stopwatch knows about that time doesn’t help you: you’ll have to output that time in such a way that you can read it. And you want to be able to do that in a released version of your app, not in – not compiler optimized – debug mode. That’s where Tracing comes in.

The Stopwatch and Tracing are demonstrated in a simple Console Application.

Let’s look at the code!

You can download this code from github

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
using System.IO;

namespace ReadySetGo
{
    class Program
    {
        static void Main(string[] args)
        {

            // Instantiate a stopwatch
            Stopwatch sw = new Stopwatch();

            // Init the tracing
            // Output to the system tempfolder
            String fileLocation = Path.Combine(Path.GetTempPath(), "MyTraceFile.txt");
            Stream outputFile = File.Create(fileLocation);

            // Setup the tracing
            TextWriterTraceListener textListener = new TextWriterTraceListener(outputFile);
            TraceSource traceSource = new TraceSource("Stopwatch Trace", SourceLevels.All);

            traceSource.Listeners.Clear(); // remove the default ConsoleTraceListener
            traceSource.Listeners.Add(textListener); // add our textlistener

            sw.Start(); // start the stopwatch

            traceSource.TraceEvent(TraceEventType.Verbose, 100, "Invoking DoSomeHeavyWork");
            DoSomeHeavyWork();

            sw.Stop();// stop the stopwatch

            Console.WriteLine("Tracefile written to {0}", fileLocation);

            if (sw.ElapsedMilliseconds > 1000)
            {
                traceSource.TraceEvent(TraceEventType.Warning, 100, "DoSomeHeavyWork took {0} miliseconds", sw.ElapsedMilliseconds.ToString());
            }
            else
            {
                traceSource.TraceEvent(TraceEventType.Verbose, 100, "DoSomeHeavyWork took {0} miliseconds", sw.ElapsedMilliseconds.ToString());
            }
            
            // finish up the traceSource
            traceSource.Flush();
            traceSource.Close();

            // for your convenience: show the tracefile in your default editor
            Process.Start(fileLocation);

            Console.WriteLine("Press a key to exit");
            Console.Read();

        }

        static void DoSomeHeavyWork()
        {
            List<string> lst = new List<string>();
            
            for (int i = 0; i <= 20000; i++)
            {
                if (!lst.Contains(i.ToString())){
                    lst.Add(i.ToString());
                }
            }
        }
    }
}

Let’s analyze this.

First, at line 6 we import the System.Diagnostics. The Stopwatch and Trace functionality are part of it, and so is the Process at line 54.

At line system you find System.IO. Needed because we need a Filestream, and because we use Path to get the default system’s tempdirectory.

Line 17 instantiates a Stopwatch. Easy as pressing a button..

At line 21-22 a stream is created, pointing at a file in the system’s temp directory. This is the file that will contain all tracing information.

Line 25 creates a TextWriterTraceListener. When doing traces, you fire an event at the moment you want to register/trace information. This event can be handled by multiple listeners. In this example we use the TextWriterTraceListener. Everytime an event is fired by the TraceSource, the TextWriterTraceListener catches that and writes the text to the file from the stream we created at line 21. Uhm.. TraceSource?

Line 26 creates the TraceSource. This is the object that will fire the tracing events that are writen to file by the TextWriterTraceListener. We give it the name “Stopwatch Trace”, and tell it to handle all possible trace events.

At line 28 we remove all listeners that are attached to the traceSource. We didn’t add one explicitly, however, when generating a new TraceSource, a default listener is added automatically (one that outputs the trace to the console). We don’t want that, so we remove it. Next, at line 29 we add our TextWriterTraceListener to the TraceSource.

Line 31 starts the stopwatch.

Line 33 tells the TraceSource to fire an event. The type is Verbose. You have multile types, like Critical, Error, Warnig, etc. In this case we just want to tell something, so we make it “verbose”.

You will see the number 100. This is an integer that could have any integer value. the traceSource doesn’t really use it. It only prints this number in your trace file. If you trace multiple processes, you can number those processes. E.g. all calls to webservices get the number 1000, all database transactions get the number 2000, etc. This is just for you, as reference.

Next, at line 34, we invoke a method that takes some time. The method itself contains just some code that consumes time, no other prupose. In real life, this could be a method that does some heavy database queries, or other calculations.

Line 36 stops the stopwatch, after the method has finished.

To read the stopwatch, we use the property ElapsedMilliSeconds.

If the method took more than 1000 milliseconds, the sourceTrace will fire a new event, this time as warning.

If less that 1000 milliseconds, the event will be of type “verbose”.

Note that you can use string formatting in the message (the {} substitutes).

Finally, line 50 and 51 finish the traceSource. This is important, for the traceSource uses a file stream.

Finally, at line 54, the System.Diagnostics.Process.Start method is used to show the trace file, so you do not have to find it in your temp folder yourself.

Run the code, and see what happens. This gives you a tool to find bottlenecks in your code!

Some last remarks.

The tracing is a system that fires events, handels events, and in this case even writes to a file. Note that those things come with performance loss. It’s minimal, but the more you trace, the more resources it’ll take.

If you want to use tracing in a live-application, make sure you build in a way to switch on and off the tracing, e.g. by setting a boolean.

 

 

 

C# Blog – Dynamic Types – Unmanaged Code – Excel Automation

C# is a strongly typed language. When building your project, the compiler will check if the types you are using are valid. If you enter something like

int i = "Hello there";

your code will not compile. i should be an integer value, the compiler sees that and refuses to continue.

There are however situations where you do not want the compiler to do these checks. Reason is that you simply do not know the exact type. This is somewhat common when you work with COM objects.

In that case you will want to tell the compiler to just pass the given value (or invoke the given method), and leave it to the runtime to decide if it is ok or not. You achieve this by using the keword “dynamic”.

When automating Excel, you’ll work with a com object. The dynamic type is the Excel Worksheet. Let’s start with the code, and after that analyze what is happening.

To be able to run the code, you’ll need to add a Microsoft.Office.Interop.Excel reference to your project. You can find it under “COM”, simply search for “Excel”.

You can download the full source code from github

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Office = Microsoft.Office.Interop;


namespace AutoExcel
{
    class Program
    {
        static void Main(string[] args)
        {

            // Generate some testdata
            Dictionary<string,int[]> dict = new Dictionary<string,int[]>();
            for (int i = 1; i <=500; i+=1) {
                dict.Add("Number " + i.ToString(),new int[5] { 100+i, 200+i, 300+i, 400+i, 500+i });
            }

            // Create the Excel Sheet
            var excelApp = new Office.Excel.Application();
            excelApp.Visible = true;
            excelApp.Workbooks.Add();

            // dynamic: types will not be checked at compile time
            dynamic workSheet = excelApp.ActiveSheet;
            
            try
            {
                // Generate the header
                workSheet.Cells[1, "A"] = "MY AUTOMATED EXCELSHEET";
                workSheet.Cells[2, "A"] = "Demonstrating Excel Automation";
                workSheet.Cells[4, "A"] = "FIELD NAME";
                workSheet.Cells[4, "B"] = "VALUE #1";
                workSheet.Cells[4, "C"] = "VALUE #2";
                workSheet.Cells[4, "D"] = "VALUE #3";
                workSheet.Cells[4, "E"] = "VALUE #4";
                workSheet.Cells[4, "F"] = "VALUE #5";


                // generate the value fields
                int row = 5;

                foreach (KeyValuePair<string, int[]> val in dict)
                {
                    workSheet.Cells[row, "A"] = val.Key;
                    workSheet.Cells[row, "B"] = val.Value[0];
                    workSheet.Cells[row, "C"] = val.Value[1];
                    workSheet.Cells[row, "D"] = val.Value[2];
                    workSheet.Cells[row, "E"] = val.Value[3];
                    workSheet.Cells[row, "F"] = val.Value[4];

                    row += 1;
                }
                
                //  AutoSize the columns
                for (int i = 1; i <= 5; i++)
                {
                    workSheet.Columns[i].AutoFit();
                }

                // Some layout:

                // Font type
                workSheet.Range(workSheet.Cells(1, 1), workSheet.Cells(row, 6)).Font.Name = "Arial";
                workSheet.Range(workSheet.Cells(1, 1), workSheet.Cells(1, 1)).Font.Size = 16;
                workSheet.Range(workSheet.Cells(2, 1), workSheet.Cells(row, 6)).Font.Size = 8;
                // Bold text:
                workSheet.Rows(4).Font.Bold = true;


                // Freeze the header
                workSheet.Application.ActiveWindow.SplitRow = 4;
                workSheet.Application.ActiveWindow.FreezePanes = true;

                
                // Select the first cell
                workSheet.Cells(1, 1).Select();
                
            }
            catch (Exception ex)
            {
                Console.WriteLine("Excel reported the following Error:");
                Console.WriteLine(ex.Message);
            }
            finally
            {
                // Release the com object
                System.Runtime.InteropServices.Marshal.ReleaseComObject(excelApp);
            }
            Console.WriteLine("Ready.");
            Console.Read();
        }   
    }
}

Let’s start with line 6. I included the Microsoft.Office.Interop and named it “Office”. You do not have to do this, but I found that it makes my life easier.

Line 16-20. We are making a program that generates an Excelsheet. That makes more sense with some data to show. These lines simply generate some numbers.

line 23-25 initialise the Excelapplication, and..

line 28 declares a worksheet as dynamic. This means that whatever you tell the worksheet to do, the compiler accepts it.

Line 30 to 87 take care of filling the worksheet. Note that when you enter this code, Visual Studio will not warn you if you make any typo’s.

Before explaining the “finally” block, let’s do an experiment.

Run the program. It should show an Excelsheet with some mark-up.

Now add the following line of code at line 65.

workSheet.PlayTheGuitarAsIfYourLifeDependsOnIt();

You can be pretty sure this method is not known by the worksheet. However, you can still compile and run the program. Only at runtime, an exception is thrown.

Finally, the finally block.

Com objects are not managed. It is so called unmanaged code.

Normally, when you exit an application, references to all objects are cleaned-up automatically. That is .. all managed references. Com objects are not managed, and will not be cleaned up.

You can see this happen by commenting out line 91 and start the program, close it, and repeat that several times. Close all Excel sheets. Now look in your task manager. You’ll see that a lot of “Excels” are still running in the background. The only way to end those is by ending the processes using task manager.

What happened? In your code you create Excel Com objects. Those objects generated Excelsheets. You can close the Excelsheets, but not the com objects. When you close the program, the .NET Garbage Collector cleans-up all managed objects … and because the dynamic workSheet object is not managed, it is not cleaned up by the Garbage Collector.

Imagine what happens if you generate 200 Excelsheets automatically…

Fortunately there is a way to clean up those com objects, as demonstrated in line 91. Make sure that code is always executed. The finally-block is the best place to do that.

C# Blog – Smooth as Peanut Butter: Multi-Threading with Async and Await

 

The .NET framework makes multi-threading as easy as opening a can of peanut butter. Let’s make a small project to demonstrate.

You can download the code from github.

Create a new C# WPF project in Visual Studio, and name it anything you like.

Drag a label and textbox on the mainwindow. Name the label “lblTime”.

Your XAML should looke something like below:

<Window x:Class="Butter.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Label x:Name="lblTime" Content="Label" HorizontalAlignment="Center" Margin="10,10,0,0" VerticalAlignment="Top"  Width="497"/>
        <TextBox x:Name="txtText" HorizontalAlignment="Left" Height="232" Margin="15,77,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="492"/>

    </Grid>
</Window>

Enter the following code in MainWindow.xaml.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace Butter
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            
            getTime();
        }
   
        private async void getTime(){
            
            Task<string> task = Task.Run<string>(() => {

                System.Threading.Thread.Sleep(1000);
                return DateTime.Now.ToString();

            });

            lblTime.Content = await task;
            getTime();

        }
    }
}

Run the program. What happens? The time is displayed and updated every second. In the meanwhile you can type text in the textbox without being disturbed.

By making the method getTime async, it runs in another thread than the User Interface. Let’s analyse what’s happening in that method.

An async method needs a Task. We make one that returns a string. We invoke it with a lambda (the ()=>{} thing).

The task sleeps for a second and returns the current time.

Next, we tell the content property of the label to await the task.

What happens there? Well, the code in this method stops. Anything after the await will not be executed until the task is ready and returns a value.

In the meanwhile your program continues working. You achieved that by making the method async.

When ready, the task returns a string. The label content has been waiting for that string, and only when that string is received by the label, the rest of the code in the method is executed.

And te rest of the code… invokes the method again.

 

C# Blog – Practical Inheritance and Polymorphism

Introduction

Polymorphism and inheritance tend to be heavy subjects for people that start to find their way in Object Oriented Programming. There are many, many tutorials and blogposts about this subject. Most of them have one thing in common: they use “what if”, “imagine that”,  or “you work for a major company with a customer database” scenarios, or they use simplified models that you will probably never use in real-life  – e.g. examples with animals, cats and dogs.

In this post I am going to describe a real-life usable example on how to implement inheritance and polymorphism. When you go through this post, you will have basic understanding of the concept. And you will have some code that you can easily reuse in your own development projects.

You can download the full sourcecode from github.

What are we building?

We will build a simple file browser. The application mainly uses the System.IO.FileInfo and System.IO.DirectoryInfo objects. The idea is as followed:

We will show a filebrowser list on screen. This list contains direcories and files. When an item in that list is selected, information about that item is shown. The clue here is that when that item is a directory, it will show different information then when it is a file. Also, when you double click an item, the action taken will depend on the type of item: if it is a directory, that directory will open in the list. If it is a file, nothing will happen (feel free to take action there as well.)

So, in the list we have a collection of an object that can act as a file or as a directory: that’s polymorphism. We’ll get this working by first building a  base class, and inherit two derived classes from that base class. Let’s get started!

1. Setup the GUI

We are going to use a standard WPF project for this. Open Visual Studio and start a new C# WPF Project. Call it “FileBrowser”. On the mainwindow, place the following:

  • a Label at the top left. Name it lblCurrentDirectory
  • A Listbox at the left, just below the label. Name it FileListBox
  • A Textbox at the right. Name it txtDetails

We will give the Lisbox a template, so we can show more than just a single value.  As you can see in the XAML below, in the listbox, one label is bound to a “DisplayType” field, another one is bound to a “Name” field.

Also in the listbox, two events are added: SelectionChanged and MouseDoubleClick. When entering them, make sure the handler methods are created in the code-behind (MainWindow.xaml.cs) as well.

The XAML should look something like this:

<Window x:Class="FileBrowser.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:FileBrowser"
        mc:Ignorable="d"
        Title="MainWindow" Height="550" Width="525">
    <Grid>
        <ListBox x:Name="fileListBox" HorizontalAlignment="Left" Height="459" Margin="10,52,0,0" VerticalAlignment="Top" Width="240" BorderBrush="#FF002698" SelectionChanged="fileListBox_SelectionChanged" MouseDoubleClick="fileListBox_MouseDoubleClick">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <Label Content="{Binding DisplayType}"/>
                        <Label Content=" - "/>
                        <Label Content="{Binding Name}"/>
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
        <TextBox x:Name="txtDetails" HorizontalAlignment="Left" Height="501" Margin="269,10,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="240" Background="#FFD0FFD5"/>
        <Label x:Name="lblCurrentDir" Content="" HorizontalAlignment="Left" Margin="10,11,0,0" VerticalAlignment="Top" Width="240"/>
    </Grid>
</Window>

2. Create the Base Class

The base class will be the parent of two other classes: the class that represents a file and the class that represents a directory.

In your project, add a new class named “FSBaseObject”. Code the class as in the code below:

using System;


namespace FileBrowser
{
    public abstract class FSBaseObject
    {
        public string Name { get; set; }
        public string Path { get; set; }
 
        public virtual string DisplayType { get {return "";}}

        public abstract string Details();

    }
}

As you can see, here we have the Name and DisplayType fields that we bound in the XAML. Further, the class is declared as abstract. This means that it is not possible to instantiate this class. If you want to use it, you have to use it via a derived class.

The properties Name and Path are straight forward. I have decided to make the property DisplayType a read/only virtual one, meaning that you can not set its value dynamically, and that you can override it (however, you do not have to. If you do not override it, it will retun an empty string).

The method Details() is abstract, meaning you have to override it in your derived classes.

This way, all derived classes will “share” the properties Name and Path. They can implement the property DisplayType, and they all have their “own” method Details.

3. Create the Derived Classes

We will create two derived classes: one for handling files, one for handling directories. Let’s start with the one for files. Create a new class, call it FSFileObject. Code is as below:

using System;
using System.Text;
using System.IO;

namespace FileBrowser
{
    public class FSFileObject : FSBaseObject
    {
        public FileInfo mFile { get; set; }
        public string FileSize{
            get {
                if (mFile != null)
                {
                    if (mFile.Length < 1024)
                    {
                        return string.Format("{0} B", mFile.Length);
                    } else if  (mFile.Length < 1024 * 1024)
                        {
                        return string.Format("{0:0.00} KB", (double)mFile.Length/1024);
                        }
                        else
                        {
                        return string.Format("{0:0.00} MB", (double)mFile.Length / (1024*1024));
                    }
                }
                else
                {
                    return "";
                }
            }
        }

        public override string DisplayType
        {
            get
            {
                return "File";
            }
        }

        public FSFileObject(string path)
        {
            this.Path = path;

            if (File.Exists(path))
            {
                mFile = new FileInfo(path);
                Name = mFile.Name;
            }
        }

        public override string Details()
        {
            StringBuilder sb = new StringBuilder();
            
            sb.AppendLine("Type:  file");
            sb.AppendLine("Name: " + Name);
            sb.AppendLine("Size: " + FileSize);
            
            return sb.ToString();
        }
    }
}

Line 7 shows how to declare this class as being inherited from our base class.

At line 9 we declare a property of type FileInfo. This is a System.IO object that handles file information and maipulation.

At line 10 I’ve added a property FileSize that  shows the size of the file as Bytes, Kilobytes or Megabytes, depending on its size. This is just for fun.

Line 33 shows the overriden property DisplayType. This Readonly property simply returns “File”.

Line 41 show an overloaded constructor. This constructor is called when you instantiate the class  with the “new” keyword, and provide a string as parameter. In code that would look like (example):

FSFileObject obj = new FSFileObject("C:\\temp\text.txt");

When instantiating the class like this, the property mFile is instantiated as well, containing information about the text.txt file.

Line 52 shows the overriden method Details. When called, this method will return some text that describes the file.

In as similar way, we’ll create a class for directories. Add a new class file to your project, and call it “FSDirectoryObject”. Code is as below:

using System;
using System.Text;
using System.IO;

namespace FileBrowser
{
    class FSDirectoryObject:FSBaseObject
    {
        public DirectoryInfo mDirectory { get; set; }

        public override string DisplayType
        {
            get
            {
                return "Directory";
            }
        }

        public FSDirectoryObject(string path)
        {
            this.Path = path;
            if (Directory.Exists(path))
            {
                mDirectory = new DirectoryInfo(path);
                Name = mDirectory.Name;
            }
        }

        public override string Details()
        {
            StringBuilder sb = new StringBuilder();

            sb.AppendLine("Type:  directory");
            sb.AppendLine("Name: " + Name);
            return sb.ToString();
        }
    }
}

As you can see, this class looks a lot like the FSFileObject. However, it is slighty different.

Next, we’ll actually start using these classes by adding code to MainWindow.xaml.cs.

4. MainWindow.xaml.cs

This is where it al happens. Let’s start with the code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.IO;

namespace FileBrowser
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private List<FSBaseObject> lst;

        public MainWindow()
        {
            InitializeComponent();

            lst = new List<FSBaseObject>();

            fillBox("c:\\");

        }

        private void fillBox(string mainPath)
        {
            lst.Clear();
            fileListBox.ItemsSource = null;
            lblCurrentDir.Content = mainPath;

            DirectoryInfo parentInfo = Directory.GetParent(mainPath);
            if (parentInfo != null)
            {
                FSDirectoryObject dirParent = new FSDirectoryObject(parentInfo.FullName);
                dirParent.Name = "..";

                lst.Add(dirParent);
            }

            string[] dirs = Directory.GetDirectories(mainPath);
            string[] files = Directory.GetFiles(mainPath);

            foreach (string s in dirs)
            {
                FSDirectoryObject dir = new FSDirectoryObject(s);
                lst.Add(dir);
            }

            foreach (string s in files)
            {
                FSFileObject file = new FSFileObject(s);
                lst.Add(file);
            }


            fileListBox.ItemsSource = lst;
            fileListBox.SelectedIndex = 0;

        }

        private void fileListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (fileListBox.SelectedItem != null)
            {
                txtDetails.Text = ((FSBaseObject)fileListBox.SelectedItem).Details();
            }
        }

        private void fileListBox_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            if (fileListBox.SelectedItem != null)
            {
                var d = fileListBox.SelectedItem as FSDirectoryObject;
                if (d != null)
                {
                    fillBox(d.Path);
                }
            }
        }
    }
}

Let’s look what’s happening here.

At line 24 we add a List of type FSBaseObject. That is a list that can be filled with instances of our base object. Wait, that base class was declared abstract, so we can’t make any instances, right? Correct. However, this is a post about polymorphism.. we can add instances of FSFileObject and FSDirectoryObject. In fact, we could add instances of any object, as long as it inhertis from FSBaseObject. Read on.

At line 32 we call a method and pass it the path to the root directory. This method starts at line 36. First, let’s jump to line 51.

Here we use the static build-in System.IO class Directory. It gives us a quick wat to retreive all sub-directories and files in a given directory. We fill two string arrays with the path to all sub-driectories and files within the root path that we defined in line 32 (c:\). Next we iterate through these arrays. First to create an instance of FSDirectoryObject for every subdirectory we have found, next we create an instance of FSFileDirectory for every file we have found. Every instance is added to the list from line 24.

The result is a list of type FSBaseObject, that is filled with instances of FSDirectoryObject and FSFileObject.

The code at line 42 to 49 adds another FSDirectoryObject, which point to the parent directory of directory that is currently shown.

When an item in the list is selected, the SelectionChanged handler at line 72 is called. It first converts the selected list item to an instance of FSBaseObject, next it calls the Details method. And that is where the magic starts! We take a FSBaseObject, but when we call the Details method, that method is invoked at the instance of the inherited class, which can be a FSDirectoryObject or FSFileDirectoryObject.

When you doubleclick an item in the list, the MouseDoubleClick event handler is called. At line 84 this method tries to cast the selected item as a FSDirectoryObject. If the selected item is not a FSDirectoryObject, but a  FSFileObect, the cast will return null. No action taken then. However, if the selected item is a FSDirectoryObject, the path of that directory is used to refill the listbox.

The result? A simple file browser that uses inheritance and polymorphism to handle both files and directories!