Developing applications is certainly something exciting to work on, but it is also challenging, especially if you need to solve some complex problems that involve advanced data structures and algorithms. In such cases, you often need to take care of performance to ensure that the solution will work smoothly on devices with limited resources. Such a task could be really difficult and could require significant knowledge regarding not only the programming language, but also data structures and algorithms.
Did you know that replacing even one data structure with another could cause the performance results to increase hundreds of times? Does it sound impossible? Maybe, but it is true! As an example, I would like to tell you a short story about one of the projects in which I was involved. The aim was to optimize the algorithm of finding connections between blocks on a graphical diagram. Such connections should be automatically recalculated, refreshed, and redrawn as soon as any block has moved in the diagram. Of course, connections cannot go through blocks and cannot overlap other lines, and the number of crossings and direction changes should be limited. Depending on the size and the complexity of the diagram, the performance results differ. However, while conducting tests, we have received results in the range from 1 ms to almost 800 ms for the same test case. What could be the most surprising aspect is that such a huge improvement has been reached mainly by... changing data structures of two sets.
Now, you could ask yourself the obvious question: which data structures should I use in given circumstances and which algorithms could be used to solve some common problems? Unfortunately, the answer is not simple. However, within this book, you will find a lot of information about data structures and algorithms, presented in the context of the C# programming language, with many examples, code snippets, and detailed explanations. Such content could help you to answer the aforementioned questions while developing the next great solutions, which could be used by many people all over the world! Are you ready to start your adventure with data structures and algorithms? If so, let's start!
In this chapter, you will cover the following topics:
- Programming language
- Data types
- Installation and configuration of the IDE
- Creating the project
- Input and output
- Launching and debugging
As a developer, you have certainly heard about many programming languages, such as C#, Java, C++, C, PHP, or Ruby. In all of them, you can use various data structures, as well as implement algorithms, to solve both basic and complex problems. However, each language has its own specificity, which could be visible while implementing data structures and accompanying algorithms. As already mentioned, this book will focus only on the C# programming language, which is also the main topic of this section.
The C# language, pronounced as "C Sharp", is a modern, general-purpose, strongly-typed, and object-oriented programming language that can be used while developing a wide range of applications, such as web, mobile, desktop, distributed, and embedded solutions, as well as even games. It cooperates with various additional technologies and platforms, including ASP.NET MVC, Windows Store, Xamarin, Windows Forms, XAML, and Unity. Therefore, when you learn the C# language, as well as getting to know more about data structures and algorithms in the context of this programming language, you can use such skills to create more than one particular type of software.
The current version of the language is C# 7.1. It is worth mentioning its interesting history with the following versions of the language (for example, 2.0, 3.0, and 5.0) in which new features have been added to increase language possibilities and to simplify the work of developers. When you take a look at release notes for particular versions, you will see how the language is being improved and expanded over time.
The syntax of the C# programming language is similar to other languages, such as Java or C++. For this reason, if you know such languages, you should quite easily be able to understand the code written in C#. As an example, similarly as in the languages mentioned previously, the code consists of statements that end with semicolons (;
), and curly brackets ({
and }
) are used to group statements, such as within the foreach
loop. You could also find similar code constructions, such as the if
statement, or while
and for
loops.
Developing various applications in the C# language is also simplified by the availability of many additional great features, such as Language Integrated Query (LINQ), which allows developers to get data from various collections, such as SQL databases or XML documents, in a consistent way. There are also some approaches to shorten the required code, such as using lambda expressions, expression-bodied members, getters and setters, or string interpolation. It is worth mentioning the automatic garbage collection that simplifies the task of releasing memory. Of course, the solutions mentioned are only the very limited subset of features available while developing in C#. You will see some others in the following parts of this book, together with examples and detailed descriptions.
While developing applications in the C# language, you could use various data types, which are divided into two groups, namely value types and reference types. The difference between them is very simple—a variable of a value type directly contains data, while a variable of a reference type just stores a reference to data, as shown as follows:

As you can see, a Value type stores its actual Value directly in the Stack memory, while a Reference type only stores a Reference here. The actual value is located in the Heap memory. Therefore, it is also possible to have two or more variables of a reference type that reference exactly the same value.
Of course, a difference between value and reference types is very important while programming and you should know which types belong to the groups mentioned. Otherwise, you could make mistakes in the code that could be quite difficult to find. For instance, you should remember to take care while updating the data of a reference type, because the change could also be reflected in other variables that are referencing the same object. Moreover, you should be careful while comparing two objects with the equals (=
) operator, because you could compare the reference, not the data itself, in the case of two instances of a reference type.
Note
The C# language also supports pointer types, which can be declared as type* identifier
or void* identifier
. However, such types are beyond the scope of this book. You can read more about them at: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/unsafe-code-pointers/pointer-types.
To give you a better understanding of data types, let's start with the analysis of the first group (that is, value types), which could be further divided into structs and enumerations.
Note
More information is available at: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/value-types.
Within structs, you have access to many built-in types, which could be used either as keywords or types from the System
namespace.
One of them is the Boolean
type (the bool
keyword), which makes it possible to store a logical value, that is, one of two values, namely true
or false
.
As for storing integer values, you can use one of the following types: Byte
(the byte
keyword), SByte
(sbyte
), Int16
(short
), UInt16
(ushort
), Int32
(int
), UInt32
(uint
), Int64
(long
), and UInt64
(ulong
). They differ by the number of bytes for storing values and therefore by the range of available values. As an example, the short
data type supports values in the range from -32,768 to 32,767 while uint
supports values in the range from 0 to 4,294,967,295. Another type within the integral types is Char
(char
), which represents a single Unicode character such as 'a'
or 'M'
.
In the case of floating-point values, you can use two types, namely Single
(float
) and Double
(double
). The first uses 32 bits, while the second uses 64 bits. Thus, their precision differs significantly.
What's more, the Decimal
type (the decimal
keyword) is available. It uses 128 bits and is a good choice for monetary calculations.
An example declaration of a variable in the C# programming language is as follows:
int number;
You can assign a value to a variable using the equals sign (=
), shown as follows:
number = 500;
Of course, declaration and assignment could be performed in the same line:
int number = 500;
If you want to declare and initialize an immutable value, that is, a constant, you can use the const
keyword, as shown in the following line of code:
const int DAYS_IN_WEEK = 7;
Note
More information about the built-in data types, together with the complete list of ranges, is available at: https://msdn.microsoft.com/library/cs7y5x0x.aspx.
Apart from structs, the value types contain enumerations. Each has a set of named constants to specify the available set of values. For instance, you can create the enumeration for available languages or supported currencies. An example definition is as follows:
enum Language { PL, EN, DE };
Then, you can use the defined enumeration as a data type, as shown as follows:
Language language = Language.PL; switch (language) { case Language.PL: /* Polish version */ break; case Language.DE: /* German version */ break; default: /* English version */ break; }
It is worth mentioning that enumerations allow you to replace some magical strings (such as "PL"
or "DE"
) with constant values and this has a positive impact on code quality.
Note
You can also benefit from more advanced features of enumerations, such as changing the underlying type or specifying values for particular constants. You can find more information at: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/enum.
The second main group of types is named reference types. Just as a quick reminder, a variable of a reference type does not directly contain data, because it just stores a reference to data. In this group, you can find three built-in types, namely string
, object
, and dynamic
. Moreover, you can declare classes, interfaces, and delegates.
Note
More information about the reference types is available at: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/reference-types.
There is often the necessity to store some text values. You can achieve this goal using the String
built-in reference type from the System
namespace, which is also available using the string
keyword. The string
type is a sequence of Unicode characters. It can have zero chars, one or more chars, or the string
variable can be set to null
.
You can perform various operations on string
objects, such as concatenation or accessing a particular char using the []
operator, as shown as follows:
string firstName = "Marcin", lastName = "Jamro"; int year = 1988; string note = firstName + " " + lastName.ToUpper() + " was born in " + year; string initials = firstName[0] + "." + lastName[0] + ".";
At the beginning, the firstName
variable is declared, and the "Marcin"
value is assigned to it. Similarly, "Jamro"
is set as a value of the lastName
variable. In the third line, you concatenate five strings (using the +
operator), namely, the current value of firstName
, the space, the current value of lastName
converted to the upper-case string (by calling the ToUpper
method), the string " was born in "
, and the current value of the year
variable. In the last line, the first chars from firstName
and lastName
variables are obtained, using the []
operator, as well as concatenated with two dots to form the initials, that is, M.J.
, which are stored as a value of the initials
variable.
The Format
static method could also be used for constructing the string, as follows:
string note = string.Format("{0} {1} was born in {2}", firstName, lastName.ToUpper(), year);
In this example, you specify the composite format string with three format items, namely the firstName
(represented by {0}
), upper-case lastName
({1}
), and the year
({2}
). The objects to format are specified as the following parameters.
Note
More information is available at: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/string.
It is also worth mentioning the interpolated string, which uses interpolated expressions to construct a string
. To create a string
using this approach, the $
character should be placed before "
, as shown in the following example:
string note = $"{firstName} {lastName.ToUpper()} was born in {year}";
Note
More information is available at: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/interpolated-strings.
The Object
class, declared in the System
namespace, performs a very important role while developing applications in the C# language because it is the base class for all classes. It means that built-in value types and built-in reference types, as well as user-defined types, are derived from the Object
class, which is also available by using the object
alias.
As the object
type is the base entity for all value types, it means that it is possible to convert a variable of any value type (for example, int
or float
) to the object
type, as well as to convert back a variable of the object
type to a specific value type. Such operations are named boxing (the first one) and unboxing (the other). They are shown as follows:
int age = 28; object ageBoxing = age; int ageUnboxing = (int)ageBoxing;
Note
More information is available at: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/object.
Apart from the types already described, the dynamic
one is available for developers. It allows the bypassing of type checking during compilation so that you can perform it during the run time. Such a mechanism is useful while accessing some application programming interfaces (APIs), but it will not be used in this book.
Note
More information is available at: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/dynamic.
As already mentioned, C# is an object-oriented language and supports declaration of classes together with various members, including constructors, finalizers, constants, fields, properties, indexers, events, methods, and operators, as well as delegates. Moreover, classes support inheritance and implementing interfaces. Static, abstract, and virtual members are available, as well.
An example class is shown as follows:
public class Person { private string _location = string.Empty; public string Name { get; set; } public int Age { get; set; } public Person() => Name = "---"; public Person(string name, int age) { Name = name; Age = age; } public void Relocate(string location) { if (!string.IsNullOrEmpty(location)) { _location = location; } } public float GetDistance(string location) { return DistanceHelpers.GetDistance(_location, location); } }
The Person
class contains the _location
private field with the default value set as the empty string (string.Empty
), two public properties (Name
and Age
), a default constructor that sets a value of the Name
property to ---
using the expression body definition, an additional constructor that takes two parameters and sets values of properties, the Relocate
method that updates the value of the private field, as well as the GetDistance
method that calls the GetDistance
static method from the DistanceHelpers
class and returns the distance between two cities in kilometers.
You can create an instance of the class using the new
operator. Then, you can perform various operations on the object created, such as calling a method, as shown as follows:
Person person = new Person("Mary", 20); person.Relocate("Rzeszow"); float distance = person.GetDistance("Warsaw");
Note
More information is available at: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/class.
In the previous section, a class was mentioned that could implement one or more interfaces. It means that such a class must implement all methods, properties, events, and indexers, that are specified in all implemented interfaces. You can easily define interfaces in the C# language using the interface
keyword.
As an example, let's take a look at the following code:
public interface IDevice { string Model { get; set; } string Number { get; set; } int Year { get; set; } void Configure(DeviceConfiguration configuration); bool Start(); bool Stop(); }
The IDevice
interface contains three properties, namely those representing a device model (Model
), serial number (Number
), and production year (Year
). What's more, it has signatures of three methods, which are Configure
, Start
, and Stop
. When a class implements the IDevice
interface, it should contain the mentioned properties and methods.
Note
More information is available at: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/interface.
The delegate
reference type allows specification of the required signature of a method. The delegate could then be instantiated, as well as invoked, as shown in the following code:
delegate double Mean(double a, double b, double c); static double Harmonic(double a, double b, double c) { return 3 / ((1 / a) + (1 / b) + (1 / c)); } static void Main(string[] args) { Mean arithmetic = (a, b, c) => (a + b + c) / 3; Mean geometric = delegate (double a, double b, double c) { return Math.Pow(a * b * c, 1 / 3.0); }; Mean harmonic = Harmonic; double arithmeticResult = arithmetic.Invoke(5, 6.5, 7); double geometricResult = geometric.Invoke(5, 6.5, 7); double harmonicResult = harmonic.Invoke(5, 6.5, 7); }
In the example, the Mean
delegate specifies the required signature of the method for calculating the mean value of three floating-point numbers. It is instantiated with the lambda expression (arithmetic
), anonymous method (geometric
), and named method (harmonic
). Each delegate is invoked by calling the Invoke
method.
Note
More information is available at: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/delegate.
While reading the book, you will see many examples presenting data structures and algorithms, together with detailed descriptions. The most important parts of the code will be shown directly in the book. Moreover, complete source code will be available to download. Of course, you can only read the code from the book, but it is strongly recommended to write such code on your own, and then launch and debug the program to understand how various data structures and algorithms operate.
As already mentioned, the examples shown in the book will be prepared in the C# language. To keep things simple, the console-based applications will be created, but such data structures could be used in other kinds of solutions as well.
The example projects will be created in Microsoft Visual Studio 2017 Community. This Integrated Development Environment (IDE) is a comprehensive solution for developing various kinds of projects. To download, install, and configure it, you should:
- Open the website https://www.visualstudio.com/downloads/ and choose the
Free download
option from theVisual Studio Community 2017
section just below theVisual Studio Downloads
header. The download process of the installer should begin automatically. - Run the downloaded file and follow the instructions to start the installation. When the screen presenting possible options is shown, choose the
.NET desktop development
option, as shown in the following screenshot. Then, clickInstall
. The installation could take some time, but its progress could be observed using theAcquiring
andApplying
progress bars.

- When the message
Installation succeeded!
is shown, click on theLaunch
button to start the IDE. You will be asked to sign in with the Microsoft account. Then, you should choose suitableDevelopment Settings
(such asVisual C#
) in theStart with a familiar environment
section. Moreover, you should choose the color theme fromBlue
,Blue (Extra Contrast)
,Dark
, andLight
. At the end, click on theStart Visual Studio
button.
Just after launching the IDE, let's proceed by creating a new project. Such a process will be performed many times while reading the book to create the example applications according to information provided in particular chapters.
To create a new project:
- Click on
File
|New
|Project
in the main menu. - Choose
Installed
|Visual C#
|Windows Classic Desktop
on the left in theNew Project
window, as shown in the following screenshot. Then, click onConsole App (.NET Framework)
in the middle. You should also type a name of the project (Name
) and a name of the solution (Solution name
), as well as select location for the files (Location
) by pressing theBrowse
button. At the end, click onOK
to automatically create the project and generate the necessary files:

Congratulations, you have just created the first project! But what is inside?
Let's take a look at the Solution Explorer
window, which presents the structure of the project. It is worth mentioning that the project is included in the solution with the same name. Of course, a solution could contain more than one project, which is a common scenario while developing more complex applications.
Note
If you cannot find the Solution Explorer
window, you could open it by choosing the View
| Solution Explorer
option from the main menu. In a similar way, you could open other windows, such as Output
or Class View
. If you cannot find a suitable window (for example, C# Interactive
) directly within the View
option, let's try to find it in the View
| Other Windows
node.
The automatically generated project (named GettingStarted
) has the following structure:
- The
Properties
node with one file (AssemblyInfo.cs
) that contains general information about the assembly with the application, such as about its title, copyright, and version. The configuration is performed using attributes, for example,AssemblyTitleAttribute
andAssemblyVersionAttribute
. - The
References
element presents additional assemblies or projects that are used by the project. It is worth noting that you could easily add references by choosing theAdd Reference
option from the context menu of theReferences
element. Moreover, you could install additional packages using theNuGet Package Manager
, which could be launched by choosingManage NuGet Packages
from theReferences
context menu.
Note
It is a good idea to take a look at packages already available before writing the complex module on your own because a suitable package could be already available for developers. In such a case, you could not only shorten the development time, but also reduce the chance of introducing mistakes.
- The
App.config
file contains the Extensible Markup Language (XML)-based configuration of the application, including the number of the minimum supported version of the .NET Framework platform. - The
Program.cs
file contains the code of the main class in the C# language. You could adjust the behavior of the application by changing the following default implementation:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace GettingStarted { class Program { static void Main(string[] args) { } } }
The initial content of the Program.cs
file contains the definition of the Program
class within the GettingStarted
namespace. The class contains the Main
static method, which is called automatically when the application is launched. The five using
statements are included as well, namely System
, System.Collections.Generic
, System.Linq
, System.Text
, and System.Threading.Tasks
.
Before proceeding, let's take a look at the structure of the project in the file explorer, not in the Solution Explorer
window. Are such structures exactly the same?
Note
You could open the directory with the project in the file explorer by choosing the Open Folder in File Explorer
option from the context menu of the project node in the Solution Explorer
window.
First of all, you can see the bin
and obj
directories, which are generated automatically. Both contain Debug
and Release
directories, whose names are related to the configuration set in the IDE. After building the project, a subdirectory of the bin
directory (that is, Debug
or Release
) contains .exe
, .exe.config
, and .pdb
files, while the subdirectory in the obj
directory—for example—contains .cache
and some temporary .cs
files. What's more, there is no References
directory, but there are .csproj
and .csproj.user
files with XML-based configurations of the project. Similarly, the solution-based .sln
configuration file is located in the solution's directory.
Note
If you are using a version control system, such as SVN or Git, you could ignore the bin
and obj
directories, as well as the .csproj.user
file. All of them can be generated automatically.
If you want to learn how to write some example code, as well as launch and debug the program, let's proceed to the next section.
Many examples shown in the following part of the book will require interaction with the user, especially by reading input data and showing output. You can easily add such features to the application, as explained in this section.
The application can read data from the standard input stream using a few methods from the Console
static class from the System
namespace, such as ReadLine
and ReadKey
. Both are presented in the examples in this section.
Let's take a look at the following line of code:
string fullName = Console.ReadLine();
Here, you use the ReadLine
method. It waits until the user presses the Enter key. Then, the entered text is stored as a value of the fullName
string variable.
In a similar way, you can read data of other types, such as int
, as shown as follows:
string numberString = Console.ReadLine(); int.TryParse(numberString, out int number);
In this case, the same ReadLine
method is called and the entered text is stored as a value of the numberString
variable. Then, you just need to parse it to int
and store it as a value of the int
variable. How can you do that? The solution is very simple—use the TryParse
static method of the Int32
struct. It is worth mentioning that such a method returns a Boolean value, indicating whether the parsing process has finished successfully. Thus, you can perform some additional actions when the provided string
representation is incorrect.
A similar scenario, regarding the DateTime
structure and the TryParseExact
static method, is shown in the following example:
string dateTimeString = Console.ReadLine(); if (!DateTime.TryParseExact( dateTimeString, "M/d/yyyy HH:mm", new CultureInfo("en-US"), DateTimeStyles.None, out DateTime dateTime)) { dateTime = DateTime.Now; }
This example is more complicated than the previous one, so let's explain it in detail. First of all, the string representation of the date and time is stored as a value of the dateTimeString
variable. Then, the TryParseExact
static method of the DateTime
struct is called, passing five parameters, namely the string representation of the date and time (dateTimeString
), the expected format of the date and time (M/d/yyyy HH:mm
), the supported culture (en-US
), the additional styles (None
), as well as the output variable (dateTime
) passed by reference using the out
parameter modifier.
If the parsing is not completed successfully, the current date and time (DateTime.Now
) is assigned to the dateTime
variable. Otherwise, the dateTime
variable contains the DateTime
instance consistent with the string
representation provided by the user.
Note
While writing the part of code involving the CultureInfo
class name, you could see the following error: CS0246 The type or namespace name 'CultureInfo' could not be found (are you missing a using directive or an assembly reference?)
. This means that you do not have a suitable using
statement at the top of the file. You can easily add one by clicking on the bulb icon shown in the left-hand margin of the line with the error and choosing the using System.Globalization;
option. The IDE will automatically add the missing using
statement and the error will disappear.
Apart from reading the whole line, you can also get to know which character or function key has been pressed by the user. To do so, you can use the ReadKey
method, as shown in the following part of code:
ConsoleKeyInfo key = Console.ReadKey(); switch (key.Key) { case ConsoleKey.S: /* Pressed S */ break; case ConsoleKey.F1: /* Pressed F1 */ break; case ConsoleKey.Escape: /* Pressed Escape */ break; }
After calling the ReadKey
static method and once any key has been pressed by a user, information about the pressed key is stored as the ConsoleKeyInfo
instance (that is, key
, in the current example). Then, you use the Key
property to get an enumeration value (of ConsoleKey
) representing a particular key. At the end, the switch
statement is used to perform operations depending on the key that has been pressed. In the example shown, three keys are supported, namely S, F1, and Esc.
Now, you know how to read input data, but how can you ask questions to the user or present results on the screen? The answer, together with examples, is shown in this section.
Similarly as in the case of reading data, operations related to the standard output stream are performed using methods of the Console
static class from the System
namespace, namely Write
and WriteLine
. Let's see them in action!
To write some text, you can just call the Write
method, passing the text as a parameter. An example of code is as follows:
Console.Write("Enter a name: ");
The preceding line causes the following output to be shown:
Enter a name:
What's important here is that the written text is not followed by the line terminator. If you want to write some text and move to the next line, you can use the WriteLine
method, as shown in the following code snippet:
Console.WriteLine("Hello!");
After executing this line of code, the following output is presented:
Hello!
Of course, you can also use Write
and WriteLine
methods in more complex scenarios. For example, you can pass many parameters to the WriteLine
method, namely the format and additional arguments, as shown in the following part of the code:
string name = "Marcin"; Console.WriteLine("Hello, {0}!", name);
In this case, the line will contain Hello
, a comma, a space, a value of the name
variable (that is, Marcin
), as well as the exclamation mark. The output is shown as follows:
Hello, Marcin!
The next example presents a significantly more complex scenario of writing the line regarding the confirmation of a table reservation at a restaurant. The output should have the format Table [number] has been booked for [count] people on [date] at [time]
. You can achieve this goal by using the WriteLine
method, as shown as follows:
string tableNumber = "A100"; int peopleCount = 4; DateTime reservationDateTime = new DateTime( 2017, 10, 28, 11, 0, 0); CultureInfo cultureInfo = new CultureInfo("en-US"); Console.WriteLine( "Table {0} has been booked for {1} people on {2} at {3}", tableNumber, peopleCount, reservationDateTime.ToString("M/d/yyyy", cultureInfo), reservationDateTime.ToString("HH:mm", cultureInfo));
The example starts with a declaration of four variables, namely tableNumber
(A100
), peopleCount
(4
), and reservationDateTime
(10/28/2017 at 11:00 AM), as well as cultureInfo
(en-US
). Then, the WriteLine
method is called passing five parameters, namely the format string followed by arguments that should be shown in the places marked with {0}
, {1}
, {2}
, and {3}
. It is worth mentioning the last two lines, where the string presenting date (or time) is created, based on the current value of the reservationDateTime
variable.
After executing this code, the following line is shown in the output:
Table A100 has been booked for 4 people on 10/28/2017 at 11:00
Of course, in real-world scenarios, you will use read- and write-related methods in the same code. For example, you can ask a user to provide a value (using the Write
method) and then read the text entered (using the ReadLine
method).
This simple example, which is also useful in the next section of this chapter, is shown as follows. It allows the user to enter data relating to the table reservation, namely the table number and the number of people, as well as the reservation date. When all of the data is entered, the confirmation is presented. Of course, the user will see information about the data that should be provided:
using System; using System.Globalization; namespace GettingStarted { class Program { static void Main(string[] args) { CultureInfo cultureInfo = new CultureInfo("en-US"); Console.Write("The table number: "); string table = Console.ReadLine(); Console.Write("The number of people: "); string countString = Console.ReadLine(); int.TryParse(countString, out int count); Console.Write("The reservation date (MM/dd/yyyy): "); string dateTimeString = Console.ReadLine(); if (!DateTime.TryParseExact( dateTimeString, "M/d/yyyy HH:mm", cultureInfo, DateTimeStyles.None, out DateTime dateTime)) { dateTime = DateTime.Now; } Console.WriteLine( "Table {0} has been booked for {1} people on {2} at {3}", table, count, dateTime.ToString("M/d/yyyy", cultureInfo), dateTime.ToString("HH:mm", cultureInfo)); } } }
The preceding code snippet is based on the parts of code shown and described previously. After launching the program and entering the necessary data, the output could look as follows:
The table number: A100The number of people: 4The reservation date (MM/dd/yyyy): 10/28/2017 11:00Table A100 has been booked for 4 people on 10/28/2017 at 11:00Press any key to continue . . .
When the code is created, it is a good idea to improve its quality. One of the interesting possibilities associated with the IDE is related to removing unused using
statements, together with sorting the remaining ones. You can easily perform such an operation by choosing the Remove and Sort Usings
option from the context menu in the text editor.
Unfortunately, the written code doesn't always work as expected. In such a case, it is a good idea to start debugging to see how the program operates, find the source of the problem, and correct it. This task is especially useful for complex algorithms, where the flow could be complicated, and therefore quite difficult to analyze just by reading the code. Fortunately, the IDE is equipped with various features for debugging that will be presented in this section.
First of all, let's launch the application to see it in action! To do so, you just need to select a proper configuration from the drop-down list (Debug,
in this example) and click on the button with the green triangle and the Start
caption in the main toolbar, or press F5. To stop debugging, you can choose Debug
| Stop Debugging
or press Shift + F5.
Note
You can also run the application without debugging. To do so, choose Debug
| Start Without Debugging
from the main menu or press Ctrl + F5.
As already mentioned, there are various debugging techniques, but let's start with breakpoint-based debugging, since it is one of the most common approaches offering huge opportunities. You can place a breakpoint in any line of the code. The program will stop as soon as the line is reached, before executing it. Then, you can see the values of particular variables to check whether the application works as expected.
To add a breakpoint, you can either click on the left-hand margin (next to the line on which the breakpoint should be placed) or place the cursor on the line (where the breakpoint should be added) and press the F9 key. In both cases, the red circle will be shown, as well as the code from the given line will be marked with a red background, as shown in line 17
in the following screenshot:

When a line with the breakpoint is reached while executing the program, it stops, and the line is marked with the yellow background and the margin icon changes, as shown in line 15
in the screenshot. Now, you can check the value of the variable by simply moving the cursor over its name. The current value will appear in the ToolTip
.
You can also click on the pin icon located on the right-hand side of the ToolTip
to pin it in the editor. Its value will then be visible without the necessity of moving the cursor over the name of the variable. Such a value will be automatically refreshed as soon as it has changed. The result is presented in the following screenshot.
The IDE could adjust its appearance and features depending on the operations performed currently. For example, while debugging, you have access to some special windows, such as Locals
, Call Stack
, and Diagnostic Tools
. The first shows available local variables together with their types and values. The Call Stack
window presents information about the following called methods. The last one (namely Diagnostic Tools
) shows information about memory and CPU usage, as well as events.
Moreover, the IDE supports conditional breakpoints that stop execution of the program only if the associated Boolean expression is evaluated to true
. You can add a condition to a given breakpoint by choosing the Conditions
option from the context menu, which is shown after right-clicking on the breakpoint icon in the left-hand margin. Then, the Breakpoint Settings
window appears, where you should check the Conditions
checkbox and specify the Conditional Expression
, such as the one shown in the following screenshot. In the example, execution will stop only when the value of the count
variable is greater than 5
, that is, count > 5
:

When the execution is stopped, you can use the step-by-step debugging technique. To move execution of the program to the next line (without incorporating another breakpoint), you can click on the Step Over
icon in the main toolbar or press F10. If you want to step into the method, which is called in the line where the execution has stopped, just click on the Step Into
button or press F11. Of course, you can also go to the next breakpoint by clicking on the Continue
button or by pressing F5.
The next interesting feature, available in the IDE, is called Immediate Window
. It allows developers to execute various expressions when the program execution is stopped using the current values of the variables. You just need to enter an expression in the Immediate Window
and press the Enter key. The example is shown in the following screenshot:

Here, the lower-case version of the table number is returned by executingtable.ToLower()
. Then, the total number of minutes between the current date and the dateTime
variable is calculated and shown in the window.
This was only the first chapter of the book, but it contained quite a lot of information that will be useful while reading the remaining ones. At the beginning, you saw that using proper data structures and algorithms is not an easy task, but could have a significant impact on the performance of the developed solution. Then, the C# programming language was briefly presented with a focus on showing various data types, both value and reference ones. Classes, interfaces, and delegates were also described.
In the following part of the chapter, the process of installation and configuration of the IDE was presented. Then, you learned how to create a new project, and its structure has been described in details. Next, you saw how to read data from the standard input stream, as well as how to write data to the standard output stream. The read- and write-related operations were also mixed into one example.
At the end of the chapter, you saw how to run the example program, as well as how to debug it using breakpoints and step-by-step debugging to find the source of the problem. What's more, you learned the possibilities of the Immediate Window
feature.
After this introduction, you should be ready to proceed to the next chapter and see how to use arrays and lists, as well as accompanying algorithms. Let's go!