Learn C# in 30 minutes
Learn C# in 30 minutes
Prateek Singh and Deepak Singh Dhami
Buy on Leanpub

Learn C# basics in 30 minutes

In this book we are going to learn the key characteristics of C# language and brief history of its evolution over the years. Then we will look into the very basics of C# language, starting from creating your ‘Hello World’ program and understanding a general structure and organization of C# program. Extending to learning the underlying framework and concepts that compile and executes your C# program. Finally we will learn the elements of C# programming language such as Data Types, Variables, Class, Objects, Loops, Conditional statement and Exception Handling.

Let’s begin.

C# Language

C# is a powerful, flexible and very popular modern programing language, which is simple and easy to learn and at the same time elegant as a programming language of few words. C# is used for a wide range of reasons but the popularity lies in its use in building cross platform applications, websites, games and cloud services.

Key Characteristics

C# have some modern features and wide variety of applications and use cases, but these are possible because of the following key characteristics it offers:

  • Modern - C# was designed keeping in mind that it supports all modern day functionalities and provides features to cater modern software development needs. Some of the modern programming language features are automatic garbage collection, lambda expressions, advanced debugging, exception handling and most importantly security.
  • Easy to learn - It is a high-level language and fairly simple to digest, because it is somewhat similar to English language. More than that, C# is a C-styled language and if you have experience with C, C++ or Java, then you can very easily get familiar with the syntax and learn the language fast.
  • Open source - .NET Core and the C# compilers are both open source under .Net Foundation and available on GitHub. The community can participate in the C# language development along with Microsoft who owns and governs the changes.
  • Cross platform - Developers can build .NET applications that can be deployed on Windows, Linux, and MacOS and more than that deployed in containers or cloud.
  • Object Oriented - C# is object oriented programming language and concepts of object-oriented programming language like encapsulation, inheritance, and polymorphism are all supported, which makes development and maintenance of code easier as the project grows compared to a Procedure-oriented programming language.
  • Type safety - C# enforces type safety by limiting ways of interaction of objects by the object type. Only operations are permitted by type definition and are applied to the object, that means type casting objects to incompatible data type is restricted.
  • Robust and Versatile - You can use C# to create cross platform client applications, Web services, distributed components, cloud applications, database applications, Internet of Things (IoT) and now artificial intelligence and Machine learning.
  • Modular - C# supports modular software development, that means applications can be written in chunks or pieces of code as in functions, classes etc that are reusable, easy to modify and extensible.
  • Secure - .Net provides many useful classes and services to enable developers to secure their code with prebuilt algorithms like AES, that have stood the test of time. More than data you also get a Data protection API (DAPI) that provides classes for cryptography that can be leveraged by developers to encrypt data and secure their applications.
  • Evolving - C# is the fastest evolving programming language since its announcement and initially it was only designed to develop Windows client applications, but today it can do pretty much anything. Every year new features are added to the language, and this is all possible because of Microsoft and the strong open-source community behind it.

A Brief History of CSharp

C# was developed as part of the .NET framework initiative at Microsoft in 1999, by a team lead by Anders Hejlsberg, who had designed several popular and successful programming languages, like Turbo Pascal, Delphi etc. The C# was developed with a design goal to develop a programming language that is simple, general-purpose, and object-oriented. But with time C# evolved into a much mature and versatile programming language and the following table represents the features added in each version since it was announced.

Version Year Features
1.0 2002-03 Object Oriented, Classes, Flexible, Typesafe, Managed, Garbage Collection, Cross-platform
2.0 2005 Generics, Anonymous Methods, Iterators, Partial types, Nullable value types
3.0 2007 Expression trees, LINQ, Lambda Expression, Extension Method, Anonymous types
4.0 2010 Dynamic Binding, Named and Optional Parameters
5.0 2012 Async Programming
6.0 2015 Exception filters, Auto property initializers, Null propagator, String interpolation and nameof operator, Await in catch/finally block
7.0 2017 Tuples, Local functions, Out variables, Pattern matching, Throw expressions
7.1 2017 Async main, Default literal expressions, Inferred tuple element names
7.2 2017 private and protected access modifier, Non-trailing named arguments, Leading underscores in numeric literals
7.3 2018 Accessing fixed fields without pinning, Reassigning ref local variables, Using initializers on stackalloc arrays, Using fixed statements with any type that supports a pattern, Using additional generic constraints
8.0 2019 Readonly member, ranges and indices, switch expressions, static local functions, Null-coalescing assignment

Compilers, Runtime and .NET Framework

C# is a programming language and .NET is a blanket term to cover both the .NET Framework, which is an application framework library and the Common Language Runtime (CLR) which is the runtime in which .NET assemblies are run.

Modern day software developers usually work on programming languages that are high level abstractions and the majority of us don’t understand how our code actually runs down to the level of processor. I mean this is the purpose of modern programming languages to make it simple for developers to focus on problem solving, rather than understand details of computers and underlying architecture.

Let’s take a step back and understand: how a C# program executes under the hoods? it my be good exercise for us to learn how C# and .Net work together to provide us the intended results.

  1. First we write the source code in C# and let’s suppose to save it in a file named: FirstProgram.cs and then we compile it with all the required resources and references.
  2. A compiler which is a program that converts the source code into an intermediate language and saves that into a file FirstProgram.exe or FirstProgram.dll with .dll or .exe extension. This intermediate language is also known as Microsoft Intermediate Language (MSIL).
  3. The computer processor still doesn’t understand the intermediate language and can only work on native\machine codes. That is why we have another program called ‘Common Language Runtime’ (CLR) that uses a ‘Just-In-Time’ (JIT) compiler to transform this intermediate language into machine code in runtime.

    A Just-In-Time compiler uses the .Net Framework’s extensive library of more than 4000 classes to provide a wide variety of useful functionalities like Windows Forms, Cryptography, File handling etc.

  4. The machine code native code that a computer can understand is nothing but a set of instructions for the computer to perform, which are generally very low-level, like memory allocation etc.
Figure 1-1. C# Code compilation and execution

On a high-level these steps can also be categorized into two parts:

  1. Compile Time - Transformation of source code to intermediate language.
  2. Run time - Conversion of intermediate language to machine code and executing machine code instructions.

Program Structure and Organization

In this subsection we will learn, some key organizational concepts that enable developers to structure their C# code in:

  • Program
  • Namespace
  • Class
  • Members
  • Assemblies

Program, Assemblies and Hello World

A C# program consists of one or more source code files, that contains Classes, methods, properties separated in namespaces and when the C# program is compiled, then these are packaged into assemblies with extension .exe for applications and .dll for libraries.

Since, it’s like an old tradition to introduce new programming language to the readers using a ‘Hello World!’ program, so keeping that in mind here are the steps to create your first Hello World program in C#:

To create a basic console application using .Net Core simply run the following command from PowerShell or Windows Command prompt:

dotnet new console --output app

This will create a new console application project and scaffold a folder named: app with the bare minimum files required. One important file created in this folder is program.cs where .cs extension refers to the C# Hello Program or source code file.

Example 1-1. Hello World in C#
using System;
namespace app
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
        }
    }
}
Figure 1-2. Creating your first program in C#

The purpose of this Hello world program is to help you understand the basic syntax and requirements of a C# program, Lets try to understand everything in this program, by breaking it line by line:

  • using System; - The using keyword is used to call class libraries which are required to execute the project. Here System is the class library, that is required to call the Console.WriteLine() method later in the Hello world program.
  • namespace app - Just like we have System class library we can also create custom class libraries like ‘app’ using the namespace keyword, which helps to organize our classes.
  • class Program - Class is a blueprint or template that help define a type. A class has a name like ‘Program’ and can contain variables, methods and other types. Every C# program must have a class definition.
  • static - This is a special keyword, and when it is used with a method then the method can be called or accessed directly without creating instance of class in which it is defined.
  • void - It is a return type of the method which means that the method doesn’t returns any value.
  • Main() - This is the entry point of the program that means in a console application, the first statement in the Main() method is the starting point of the program.
  • string[] args - This is used to supply command-line arguments, where string[] is an array of String data type with array name ‘args
  • Console.WriteLine("Hello World!"); - Console is a class in System namespace, that has a method called WriteLine() that can write a string value like “Hello World!” supplied to the standard output.
  • ; - Semicolons are statement terminators, which mean any expression, assignment or declaration statements are supposed to terminate with a semicolon, that represents line termination character.
  • { } - Curly braces represent start and end of code block, like start or end of a class or method body.

Now that we understand the Hello world program, we can go ahead and run the program using the dotnet run command, which is a convenient way to run your application source code from the command line, make sure you are in the application directory when you are running this command. The dotnet run can automatically build the project if necessary, but you can also explicitly build the project using the command: dotnet build that builds but doesn’t run the program.

dotnet run
dotnet build

The dotnet build command converts all the project source code, references and dependencies into intermediate language (IL) with extension .dll and depending upon the type of project and the settings\properties in the project file: <project name>.csproj other files like executable .exe will be included in the project build.

Figure 1-3. C# project file .csproj

All the output file on build will be written by default to the location: <project name>\bin\<configuration>\<target>

Figure 1-4. Build a C# project into assemblies and executable

Namespaces

C# Namespaces are used to neatly organize classes as the project continues to grow, more than that Namespaces also provide a way to separate your code and avoid any class naming conflicts. In other words Namespaces are containers which contain other namespaces and classes that are logically related to each other.

To define a namespace we simply use keyword: namespace followed by the name of your namespace, like demo as demonstrated in the following example, and then all the classes: Class1, Class2 and so on.. are defined in this container within the body of the namespace enclosed by the brackets { }.

Example 1-2. C# Namespaces
using System;

namespace Demo
{
    class Class1
    {
        String s1 = "This is Class1";
    }

    class Class2
    {
        String s1 = "This is Class2";
    }
}

In the above example, System is a namespace defined in .Net Framework that contains the fundamental and base classes like Console, which has a method called WriteLine() that can write the specified data to the standard output stream. At the top of the program, in our example, we used using directive followed by the name of namespace , which allows the use of types in the namespace, without fully qualified name like Console.WriteLine() instead of System.Console.WriteLine().

Class

In simple terms a class is a blueprint or prototype that is used to define an object, which is a programmatic representation of a real world object that has characteristics or properties such as color, height, width and can perform functionalities such as start, stop, move, jump etc.

Let’s take an example, that we want to define a Car in C#, first thing we have do is create a class declaration for that using the following code snippet:

Example 1-3. C# Classes
using System;
public class Car
{
    public string color = "red"; // property
    public int maxSpeed = 200; // property

    public void start() // function
    {
        Console.WriteLine("Car started");
    }

    public void stop() // function
    {
        Console.WriteLine("Car stopped");
    }
}

Here, the first thing you notice is public which is an access modifier, followed by the keyword class and the name of the class. then the body of class is enclosed in open and close brackets { }.

Members

All the constants, properties and methods defined inside the body of a class are known as members of that class, as shown in the Example 1-3 of the above subsection. Generally speaking members can be:

  1. Property - Properties are attributes or characteristics of the class, which by default are private but, if they are public they can be accessed using class objects to change the characteristics of the Object. Like for Car Class, color, maxSpeed are properties that can have some default value like color = "red", but these can be accessed and changed on each instance of this class called object.
  2. Method - Methods are functions defined in a class, which have access to all the members of a class. The purpose is to perform a functionality for the object of the class, for example Car Class has methods like: start() and stop().

C# language doesn’t support any global variables or methods, that means all the entry points of the program, which the Main() method is also defined inside a class. More than that class is just a blueprint and we have to instantiate the class or in other words create objects of the class to access the members.

To create an object from class we use the following syntax in C#:

<Name Of Class> Object = new <Name Of Class>();

So, to create a tesla object from Car class, we will use the new keyword as demonstrated in the Example 1-4, and then access the members of this object using the (.) Dot operator in C#.

Example 1-4. Create an Object from C# Class
public class example {
    static void Main(string[] args){
        Car tesla = new Car();
        System.Console.WriteLine(tesla.color);
        System.Console.WriteLine(tesla.maxSpeed);
        tesla.start();
    }
}
Figure 1-5. Creating Object from C# Class and accessing members

C# Programming Elements

This subsection provides an overview and basic information about all elements of C# programming language.

Comments

Comments in any programming language are a handy way to document the code to make it more readable, and makes it easy for other developers to understand it. Any commented part in code is not executed and can also be used when testing alternative code.

In C#, to create a single-line comment we use double forward-slash ( // ), whereas a multi-line comment starts with /* and ends with */.

Example 1-5. Single and multi-line comments in C#
using System;
public class HelloWorld
{                                      
    /* this is multi line
       comment that exist
       across multiple lines */

    static void Main(string[] args)     
    {   
        // this is a single-line comment                                
        String message = "Hello World!"; 
        Console.WriteLine(message);            
    }                                   
}

Case Sensitivity

C# is a case sensitive programming language that means book, Book and BOOK are 3 different identifiers, irrespective of the fact all three of them are the same word, but have different cases.

Example 1-6. C# is case sensitive programming language
using System;
public class Case
{
    static void Main(string[] args)
    {
        string book = "Sapiens";
        string Book = "Mastery";
        string BOOK = "Deep Work";
        Console.WriteLine($"My favorite books: {book}, {Book}, and {BOOK}.");
    }
}
Figure 1-6. C# case sensitive identifiers

Using Directive and Statement

In C# language, the using directive has three main high-level purposes, first is to provide a way to utilize the types in a namespace, so that you don’t have to fully qualify the types and functions in the namespace.

Example 1-7. Using directive on namespaces to qualify class members
using System;
public class example {
    static void Main(string[] args){
        // otherwise, need to qualify as System.Console.WriteLine()
        // instead of just Console.WriteLine()
        Console.WriteLine("Hello!");
    }
}

Second, purpose is to give developers ability to create alias for namespaces, as demonstrated in the following example:

Example 1-8. Using directive to create a namespace alias
// here 'Con' is a alias of System.Console
using Con = System.Console;
 
public class example {
    static void Main(string[] args){
        Con.WriteLine("Hello!"); // using the alias
    }
}

Finally, the third purpose is to provide an option to release resources automatically. Any object that implements an IDisposable interface, which has only one method: Dispose() where you can write the code to dispose of any resources. This is where using statement comes into picture, so that we can instantiate an object in the statement and at the end of the using statement block, Dispose() method is automatically called. Following example demonstrates this and will help you understand.

Example 1-9. C# Using statement
using System;

// class has to implement IDisposable interface
public class Message : IDisposable
{
    public void Print()
    {
        Console.WriteLine("Howdy!");
    }

    // dispose method
    public void Dispose()
    {
        Console.WriteLine("Dispose method called");
    }
}

public class example
{
    static void Main(string[] args)
    {
        using (Message msg = new Message())
        {
            msg.Print(); // this executes first
        } // at end Dispose() is called automatically

    }
}

Output:

Howdy!
Dispose method called

Types and Variables

All C# Data types or simple ‘types’ can be classified into two broad categories:

  1. Value types
  2. Reference types

Values Types

Value type data types hold a data value within its own designated memory space and they can not contain null values. Following is a list of value data types you can use in your C# programs.

.Net Type Type Alias Represents Range Default Value
System.Byte byte 8-bit unsigned integer 0 to 255 0
System.Boolean bool Boolean value True or False False
System.Char char 16-bit Unicode character U+0000 to U+ffff ‘\0’
System.Decimal decimal 128-bit precise decimal values with 28-29 significant digits (+/-)1.0 x 10-28 to (+/-)7.9 x 1028 0.0M
System.Double double 64-bit double-precision floating point type (+/-)5.0 x 10-324 to (+/-)1.7 x 10308 0.0D
System.Single float 32-bit single-precision floating point type (+/-)1.5 x 10^-45 to (+/-)3.4 x 1038 0.0F
System.Int32 int 32-bit signed integer type -2,147,483,648 to 2,147,483,647 0
System.Int64 long 64-bit signed integer type -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 0L
System.SByte sbyte 8-bit signed integer type -128 to 127 0
System.Int16 short 16-bit signed integer type -32,768 to 32,767 0
System.UInt32 uint 32-bit unsigned integer type 0 to 4,294,967,295 0
System.UInt64 ulong 64-bit unsigned integer type 0 to 18,446,744,073,709,551,615 0
System.UInt16 ushort 16-bit unsigned integer type 0 to 65,535 0

Reference Types

Reference types contain references to other objects and don’t store any actual data in a variable. In simpler words they store reference to a memory location. Reference types bring in the possibility of one or more variables to reference a single object, and similarly any action performed by any one variable changes the referenced object. C# provides some built-in reference types such as: dynamic, object, string. In order to declare your own reference types in C#, you can take advantage of the keywords: class, interface and delegate.

Following table will help you understand basic differences between value and reference types:

  Value type Reference type
Stores Actual value Memory location
Allocation Stack, member Heap
Nullable Always has value Maybe null
Default 0 null
Assignment Copying actual data Copying reference

Variables

A variable is the name of the storage location that is used to store values of data types supported by the programming language. In C# depending upon the data type of the variable, a memory location with a specific size and layout is assigned to the variable.

To define and initialize a variable we follow the below mentioned syntax:

// variable definition
<data-type> <variable-name>;

// multiple variable definition
<data-type> <variable-name1>, <variable-name2>, <variable-name3>; 

// variable definition and initialization
<data-type> <variable-name> = value;

Here, <data-type> can be one of data types that we discussed in the previous subsection such as value types: char,int,float and reference types or in other words a user defined data types: Employee, Car etc. Following are some examples to demonstrate this:

Example 1-10. Declaring and initializing C# variables
public class example
{
    static void Main(string[] args)
    {
        // single variable declaration only
        bool flag;

        // multiple variable declaration only
        int a, b, c;

        // variable declaration and initialization
        double pi = 3.14;
        char chr = 'a';
        int num, count = 5;
        int[] list = { 2, 4, 6, 8, 10 };
    }
}

When declaring a variable in your C# program, you must explicitly specify the data type, otherwise you can also use the ‘var’ keyword to let the compiler implicitly decide the type of variable at compilation time.

Operators, Operands and Expressions

Expressions are combinations or sequences of operands and operators and once an expression is evaluated, it returns a value. The operators of an expression represent operations to apply on the operands. For example: (x + y) * z is an expression in which x, y, z are operands and +, * are operators.

Operators

The operators in the C# Language can be categorized into, following 3 broad categories:

  1. Unary operator - Unary operators take one operand to perform the operation and either prefixed or postfixed to the operand. Some common use cases can be increment (++), decrement (--) and negative boolean (!) operators, below are some examples that will help you understand. Example 1-11. C# increment and decrement operators
    Example 1-11. C# increment and decrement operators
    // increment and decrement operators
    int x = 5;
    
    ++x // pre increment operator
    
    x++ // post increment operator
    --x // pre decrement operator
    
    x-- // post decrement operator
    // negative boolean operator
    
    bool flag = true;
    !flag
    !false
    !true
    
    Figure 1-7. C# Unary operators
    Figure 1-7. C# Unary operators
  1. Binary operator - Binary operators take two operands to perform the operation, and operator is in between the two operands, as shown in the following examples binary operators can be used as arithmetic (+,-,*,/,%) operators or logical OR (||) and logical AND (&&) operators. Example 1-12. C# arithmetic and logical operators
    Example 1-12. C# arithmetic and logical operators
    // arithmetic operators
    1 + 2
    13 - 12
    5 * 5
    15 / 3
    29 % 4
    
    // logical operators
    var x = true;
    var y = false;
    x || y
    x && y
    
    Figure 1-8. C# Arithmetic and Logical operators
    Figure 1-8. C# Arithmetic and Logical operators

    Relation (>,>=,<,<=,==,!=) and assignment (=) operators also fall under the category of the binary operators, following are some examples to demonstrate this:

    Example 1-13. C# relational and assignment operators
    Example 1-13. C# relational and assignment operators
    // relational operators
    1 > 0
    "ONE" == "one"
    5 <= 5
    2 != 5
    
    // assignment operators
    int x, y;
    x = 5
    y = x + 3
    
    Figure 1-9. C# Relational and Assignment operators
    Figure 1-9. C# Relational and Assignment operators

3. Ternary operator - Ternary operator is a special operator that is used in decision making or to check conditions, this operator takes three operands in syntax mentioned below:

<condition> ? <if true> : <if false>
Following is an example that will help you understand this better.
Example 1-14. C# ternary operators
int x = 5;
int y = 7;

x > y ? "x is greater than y" : "x is smaller than y"
Figure 1-10. C# Ternary operator

Basic Input and Output

In order to output something in your C# program, we can use the WriteLine() or Write() method of namespace System and class Console as demonstrated in the following example. The only difference between Write() and WriteLine() method is that the former prints the string passed as an argument and stays one the same line, while the latter prints the string and then moves to the start of the next line.

Example 1-15. C# output
public class example
{
    static void Main(string[] args)
    {
        // simply writes the string
        System.Console.Write("prints and stays on the same line");

        // writes the string followed by line terminator
        System.Console.WriteLine("prints and moves to new line");
    }
}

To take user input in a C# program, we can simply use the ReadLine() method, also included in class Console, part of namespace System.

Example 1-16. C# input
public class example
{
    static void Main(string[] args)
    {
        System.Console.WriteLine("Enter Name");
        string name = System.Console.ReadLine();
        System.Console.WriteLine($"Name entered is '{name}'");
    }
}
Figure 1-10. C# Ternary operator

Conditional statements

C# like any other high level programming language needs a mechanism to execute statements on basis on conditions, also known as Conditional Statements. Which can be further classified into two categories:

  1. Conditional Branching - if, if..else, switch
  2. Conditional Looping - for, while, do..while, foreach

Let’s look into some simple examples and understand conditional branching and we will cover conditional loop in the next subsection: “Loops and Iterations”.

If and If..Else statement

An if statement allows you to test whether a condition is met or not, if the condition is met, then the statements in the body of if will be executed.

Example 1-17. If statement
using System;

public class example{
    static void Main(string[] args){
        int x = 5;

        if (x > 3){ // condition
            Console.WriteLine("x is greater than 3");
        }
    }
}

Similarly you can also use else to execute statements when condition is not met.

Example 1-18. If..Else statement
using System;
public class example{
    static void Main(string[] args){
        int x = 5;

        if (x > 3){ // condition
            Console.WriteLine("x is greater than 3");
        }
        else{
            Console.WriteLine("x is less than or equals to 3");
        }
    }
}
Figure 1-11. C# If..Else statement

Or use multiple if..else if..else if..else to test multiple conditions and execute the statement based on if the conditions are met or not.

Example 1-19. If..Else If..Else statement
using System;
public class example{
    static void Main(string[] args){
        int x = 9;

        if (x == 0){ // condition 1
            Console.WriteLine("x is equals to 0");

        }
        else if (x > 0 && x <= 5){ // condition 2
            Console.WriteLine("x is between 1 to 5");

        }
        else if (x > 5 && x <= 10){ // condition 3
            Console.WriteLine("x is between 5 to 10");

        }
        else{ // if no conditions are met
            Console.WriteLine("x is greater than 10");
        }
    }
}

Switch statement

Switch statements are basically an enhanced version of if..elseif..else statements, and are very useful when you want to test multiple conditions without writing too much code. In simpler terms it is easy to read and less verbose.

Example 1-20. Switch statement
using System;

public class example {
    static void Main(string[] args){
        string city = "Delhi";

        switch(city){  // condition
            case "Mumbai":
                Console.WriteLine("Current city is Mumbai");
                break;
            case "Delhi":
                Console.WriteLine("Current city is Delhi");
                break;
            case "Bangalore":
                Console.WriteLine("Current city is Bangalore");
                break;
            default:
                Console.WriteLine("No city is chosen!");
                break;
        }
    }
}
Figure 1-12. C# switch statement

Loops and Iterations

Loops and Iterations in any programming language are used to repeat one or more statements over and over based on a condition.

Syntax:

For (initialize; condition; increment)  
{  
    < statement >
    < statement >
} 

Let’s take a very simple example and create a for loop to iterate numbers from 0 to 5.

Example 1-21. For loop
using System;
public class example{
    static void Main(string[] args){
        for (int i = 0; i <= 5; i++)
        {  
            Console.WriteLine(i);
        }
    }
}
Figure 1-13. C# For loop

Iteration statements are used to repeatedly execute an embedded statement. This group contains the while, do, for, and foreach statements.

Exceptions Try..Catch..Finally

When in a C# program an error occurs, C# will normally stop the further execution program and generate an error message, which is also known as an Exception or an error thrown by the program. To handle such exception C# like any other programming language has a mechanism called error handling, which basically consists of 3 blocks mentioned below:

  1. Try - Block of code which is tested or tried for errors
  2. Catch - Block of code to handle the errors. There can be more than one catch blocks.
  3. Finally - Block of code that allow developers to execute code regardless of result (exception or no exception)

So, code in the try block will be tested and if an exception is thrown it automatically gets captured by the catch block, where you can display custom messages for the exception or handle the exception by running some other statements. At last we have the finally block which will execute every time regardless of the fact an exception was thrown or not, this block is optional and can be omitted if not required. The purpose of finally block is resource cleanup, garbage collection or controlling the

Following is a simple example to demonstrate try..catch by intentionally raising a DivideByZeroException.

Example 1-22. Try..Catch block
using System;
public class example{
    static void Main(string[] args){
        try {
            int x = 1;
            int y = 0;
            var result = x / y;

            Console.WriteLine($"Result: {result}");
        }
        catch { // or catch (Exception e) {
            Console.WriteLine($"Can not divide a number by Zero!");
        }
    }
}

In the above example any error thrown in the try block will be caught in the catch block. irrespective of the fact that it is a DivideByZeroException or some other exception, which is often not a very good idea and we should only catch exceptions which we understand and want to handle. So, to specifically handle or filter a certain type of exception we can define a catch block with arguments like catch (DivideByZeroException), and even create a variable of the exception type to use it inside the catch block, which has built-in Message property.

Example 1-23. Catch block with argument filters
using System;
public class example{
    static void Main(string[] args){
        try {
            int x = 1;
            int y = 0;
            var result = x / y;

            Console.WriteLine($"Result: {result}");
        }
        catch (DivideByZeroException exception){
            Console.WriteLine($"ERROR: {exception.Message} ");
        }
    }
}
Figure 1-14. C# For loop

At last if a finally block exists, it will be executed after the execution of the try..catch block.

Example 1-24. Try..Catch..Finally block
using System;
public class example{
    static void Main(string[] args){
        try {
            int x = 1;
            int y = 0;
            var result = x / y;

            Console.WriteLine($"Result: {result}");

        } catch (DivideByZeroException exception) {
            Console.WriteLine($"ERROR: {exception.Message} ");

        } finally {
            Console.WriteLine("Finally block always executes, even when exception is thrown.");
        }
    }
}

Classes and objects

Classes are also C# types, basically a blueprint of data structure that combine properties and methods in a single unit. A C# Class is declared using the class keyword, prefixed with an access modifier: like public and followed by the body of the class and its members as shown in the following example:

Example 1-25. C# class declaration
using System;

// class declaration
public class Table{

    // class properties
    int length = 300; 
    int width = 200;
    int height = 100;
    string woodType = "Cedar";

    // class methods
    public void getDetails(){
        Console.WriteLine($"Table is made of '{woodType}' wood");
        Console.WriteLine($"Dimensions are {length}x{width}x{height}cm");
    }
}

When a class is instantiated it is called an Object and it can be used to access the properties and methods of the class from which it is instantiated using the Dot (.) operator followed by the member of the class as shown in the following example:

Example 1-26. Instantiating a C# class
using System;
public class example{
    static void Main(string[] args){

        // creating an object from 'Table' class
        Table table1 = new Table();

        // accessing method of the class
        table1.getDetails();
    }
}
Figure 1-15. C# class and object

Arrays

C# arrays are data structures that store a fixed number of homogeneous data types, grouped as a single unit. These individual data types are called elements of the array and can be accessed by its numerical index. Array indexes start at 0 so that second element is at index 1, following examples will help you understand arrays better:

Example 1-27. C# arrays
using System;
public class example{
    static void Main(string[] args){
        // array declaration
        int[] employeeId = new int[4]{1,2,3,4};
        string[] employeeName = new string[4]{"John","Bill","Susan","Mary"};

        // accessing array elements
        Console.WriteLine(employeeId[2]);
        Console.WriteLine(employeeName[3]);
        
        // updating array elements
        employeeName[2] = "Prateek";
    }
}
Figure 1-16. C# Arrays

You can also create an array of objects, such that each element of the array is an object of a class. Let’s take the same example from the previous subsection where we created a class Table, but this time we will create an array of objects as demonstrated in the following example:

Example 1-28. Array of Objects
using System;
// class declaration
public class Table{

    // class properties
    int length = 300; 
    int width = 200;
    int height = 100;
    string woodType = "Cedar";

    // class methods
    public void getDetails(){
        Console.WriteLine($"Table is made of '{woodType}' wood");
        Console.WriteLine($"Dimensions are {length}x{width}x{height}cm");
    }
}

public class example{
    static void Main(string[] args){
        // creating an array of object from 'Table' class
        Table[] tables = new Table[5];

        // instantiating class and assigning object to array index
        tables[2] = new Table();

        // accessing a object and its members, as element of the array 
        tables[2].getDetails();
    }
}
Figure 1-16. C# Array of objects

Loops

Loops and Iterations in any programming language are used to repeat one or more state- ments over and over based on a condition. Loops are broadly classfied into two sets:

  • Entry controlled - Condition to be tested is at the beginning of the loop body e.g. while, for, foreach loops.
  • Exit controlled - Testing condition is present at the end of the loop body e.g. do...while
Name Type Description
while Entry controlled Repeats a code block while a given condition is true, condition is tested before the code block execution
for Entry controlled Repeats a code block but requires variable initialization, test condition, and increment/decrement of the looop variable. Preferred where the count of iterations are known beforehand.
foreach Entry controlled Used to loop through the elements of a collection
do…while Exit controlled Tests the condition at the last, this means the code block executes at least once.

While loop

The while loop executes a block of code as long as the condition is True.

Syntax

while (boolean condition)
{
   loop statements...
}
Example 1-29. C# while loop
using System;
public class example
{
    static void Main(string[] args)
    {
        int i = 0;
        while (i < 5)
        {
            Console.WriteLine(i);
            i++;
        }
    }
}

For loop

When you know exactly how many time to loop through a code block, use the for loop.

for (initialize; condition; increment)
{
    < statement >
}
Example 1-30. C# for loop
using System;
public class example
{
    static void Main(string[] args)
    {
        for (int i = 0; i < 5; i++)
        {
            Console.WriteLine(i);
        }
    }
}

Foreach loop

Use the foreach loop to loop over a collection.

foreach ( item in collection)
{
    <statement>
}
Example 1-31. C# foreach loop
using System;
using System.Linq;
public class example
{
    static void Main(string[] args)
    {
        var intCollection = Enumerable.Range(0,5) // generate a collection of numbers from 0 to 4
        foreach (int number in intCollection)
        {
            Console.WriteLine(number);
        }
    }
}

do…while loop

This loop is a bit different than other loops discussed so far, it has the test condition at the end of the loop body. This means that the code block atleast gets executed once.

do
{
    <statement>
} while (condition)
Example 1-32. C# do…while loop
using System;
public class example
{
    static void Main(string[] args)
    {
        int i = 0;
        do
        {
            Console.WriteLine(i);
            i++;
        } while (i < 5);
    }
}

Loop control statements

Loop control statements can be used to modify the normal code execution sequence. C# provides following two control statements:

Name Description
break Terminates the loop entirely and transfers the control to the immediate statement following the loop.
continue It causes the loop to skip the remainder of the body and retest its condition before reiterating

Type Casting

The process of converting one type of data to another type is referred to as type casting. In C# it has two forms:

  • Implicit - Performed by C# in type-safe manner e.g. conversion from smaller type int to larger type long. No data is lost in these conversions.
  • Explicit - Done by users, data can be lost e.g. conversion from a larger type long to smaller type int. These requires a cast operator, specify the type that you are casting in parentheses in front of the value or varibale to be converted (see example below).

Implicit casting example:

int myInt = 10;
double myDouble = myInt; // implicit casting

Explicit casting example:

double myDouble = 9.78;
int myInt = (int) myDouble; // explicit castingm, specify the type in parentheses

Lambda Expressions

Lambda expressions are used like anonymous functions (functions without a name), with a difference that type of input doesn’t need to be specified. This makes them more flexible to use, especially with LINQ queries.

There are two types of lambda expressions:

  • Expression lambda - Comprises of the input and expression.
input => expression ;
Example 1-33. C# expression lambda
using System;
public class example
{
    static void Main(string[] args)
    {
        // generate a range of numbers from 1 to 5
        var numbers = Enumerable.Range(1,5);

        // see use of the expression lambda with the Select LINQ query
        var squares = numbers.Select(x => x * x);

        foreach (var square in squares)
        {
            System.Console.WriteLine(square);
        }
    }
}
  • Statement lambda - Consists of the input and set of statements to be executed.
input => { statements };
Example 1-34. C# statement lambda
using System;
using System.Linq;
public class example
{
    static void Main(string[] args)
    {
        // generate a range of numbers from 1 to 5
        var numbers = Enumerable.Range(1, 5);

        // define a statement lambda using the Func<T,T> delegate
        Func<int, int> square = (x) =>
        {
            var value = x * x;
            return value;
        };
        
        foreach (var number in numbers)
        {
            // use the statement lambda expression
            Console.WriteLine(square(number));
        }
    }
}

Strings and String Operations

The string is an array of characters or in other words a series of characters. Strings can be declared using .Net class System.String or using the String keywords, both are same and there is no difference.

Escape Sequences

Escape sequences are combinations of characters prefixed with of a backslash (\) and followed by a letter or by a combination of digits.

Following is the complete set of escape sequences:

Escape Sequence Description
\' single quote for character literals
\" double quote for string literals
\\ backslash
\0 Unicode
\a Alert
\b Backspace
\f Form feed
\n New line
\r Carriage return
\t Horizontal tab
\v Vertical tab
// new line character
System.Console.WriteLine("Hello world!\nThis is a new line");

// printing column and rows with horizontal tab and new-line
System.Console.WriteLine("col1\tcol2\tcol3\ncell1\tcell2\tcell3\ncell4\tcell5\tcell6\ncell7\tcell8\tcell9");

In C# we can start a string with @ symbol, that tells the compiler to ignore escape characters in the string, such strings are also known as verbatim string.

string path = @"c:\temp\myfolder";
System.Console.WriteLine(path);

String Concatenation

Concatenation is the process of appending one or more strings to the end of another string using the + operator.

string name = "John";

// string concatenations
string msg = "Hello " + name + ", How are you today?";
System.Console.WriteLine(msg);

String Interpolation

String interpolation allows users to embed variables in a string and ability to be expanded to their respective values when used with a special character $ as shown in the following example:

string firstName = "Bill";
string lastName = "Gates";

Console.WriteLine($"Hi, I'm {firstName} {lastName}");

Composite String Formatting

Composite formatting is supported by methods such as string.Format(), Console.WriteLine() or StringBuilder.AppendFormat(). These methods take string and indexed format items that are replaced by the respective placeholders in the string.

string firstName = "Bill";
string lastName = "Gates";
Console.WriteLine("Hi, I'm {0} {1}", firstName, lastName);

Accessing Chars in a String

Strings are array of characters and any character can be accessed using the respective index value as shown in the following example:

string firstName= "Bill";

// string[charIndex]
System.Console.WriteLine(firstName[2]);

for (int i = 0; i < firstName.Length; i++)
{
    System.Console.WriteLine(firstName[i]);
}

Splitting a String

A string can be split into two or more strings using the Split() method where in we can pass the character to split on. Like in the following example, we have a comma-separated string and we want to split by comma (,) to get a list of values.

// comma separated string of names
string names = "Bill Gates,Oprah Winfrey,Jeff Bejos,Tom Cruise"; 

// split string with a single char
string[] listOfNames = names.Split(',');  
foreach (string name in listOfNames)  
    System.Console.WriteLine(name);

Replace text in a String

C# has a Replace() method which accepts the substring which has to be replaced and a new value that would be replacing all the occurrences old substring. As demonstrated in the following example, we are replacing all the occurrences of substring ‘fox’ with a new substring ‘wolf’.

string original = "The quick brown fox jumps over the lazy dog";

// Substring replacement
var modified = original.Replace("fox", "wolf");
Console.WriteLine("Original sentence: "+original+"\nModified sentence: "+modified);

Trim White Space

C# Strings have 3 inbuilt methods to trim an trailing or leading white spaces from a string as shown in the following example:

string sentence = "    a sentence with trailing and leading white spaces      ";

Console.WriteLine(sentence.Trim());
Console.WriteLine(sentence.TrimStart());
Console.WriteLine(sentence.TrimEnd());

Extract Substrings from a String

In order to extract a substring from a string, we can use the Substring() method where in we can specify the starting index of the substring and the length.

string bookName = "Learn C# in 30 minutes";
System.Console.WriteLine(bookName.Substring(6, 2));

Convert a String to Char array

Converting a String to Char array is as simple as using the inbuilt method ToCharArray() on a string as demonstrated in the following example:

string name = "Bill Gates";

// convert string array to char and print
foreach(char ch in name.ToCharArray())
    System.Console.WriteLine(ch);

Convert a Char array to String

To convert a Character array to a string we can pass it to a string() constructor as shown in the following example:

var chars = new char[] {'b','i','l','l'};

// convert char array to string
string name = new string(chars);
System.Console.WriteLine(name);

Changing case of a String

Changing a string to all lower case characters and all upper case characters is as easy as calling the ToLower() and ToUpper() methods respectively on a string, but in order to change to a title case we have to use the ToTitleCase() of the CultureInfo.CurrentCulture.TextInfo class.

using System.Globalization;

string a = "Hello world";
System.Console.WriteLine(a.ToUpper());
System.Console.WriteLine(a.ToLower());

TextInfo t = CultureInfo.CurrentCulture.TextInfo;
System.Console.WriteLine(t.ToTitleCase(a));

Working with Date and Time

C# has a DateTime struct that allow us to work with dates and times and represents an instant in time.

To work with date and time in C#, create an object of the DateTime struct using the new keyword. The following creates a DateTime object with the default value.

DateTime object and static fields

We can create an object using the DateTime struct using the new keyword as shown in the following example:

DateTime d = new DateTime(); // default value 01/01/0001 00:00:00

// DateTime in specified year, month, day, hour, minute, and second
DateTime d = new DateTime(2021, 2, 23, 23, 53, 52);

DateTime also has some static fields that can provide current date time, today’s date etc.

Console.WriteLine(DateTime.Now);  // current date and time
Console.WriteLine(DateTime.UtcNow); // current date and time in UTC
Console.WriteLine(DateTime.Today); // today's date

TimeSpan

In C# a TimeSpan struct represents a time interval, and we can also use a time span to add or subtract from a DateTime object as demonstrated in the following example:

DateTime d = new DateTime(2021, 2, 23, 23, 53, 52);
TimeSpan ts = new TimeSpan(7,6,30,00);
Console.WriteLine(d.Add(ts)); // OUTPUT: 3/3/2021 6:23:52 AM
Console.WriteLine(d.Subtract(ts)); // OUTPUT: 2/16/2021 5:23:52 PM

Convert DateTime to String and Custom Formatting

DateTime objects can be converted to string using the ToString() method. The same method can also be used to for custom formatting using the DateTime format specifiers as demonstrated in the following example:

var d = DateTime.Now;

Console.WriteLine("Date in current culture: " + d.ToString("d"));
Console.WriteLine("Date in 'MM/dd/yyyy': " + d.ToString("MM/dd/yyyy"));
Console.WriteLine("Date in 'ddd, dd MMMM yyyy': " + d.ToString("ddd, dd MMMM yyyy"));
Console.WriteLine("Date in 'dddd, dd MMMM yyyy': " + d.ToString("dddd, dd MMMM yyyy"));
Console.WriteLine("Date in 'MM/dd/yyyy h:mm tt': " + d.ToString("MM/dd/yyyy h:mm tt"));
Console.WriteLine("Date in 'MMMM dd':" + d.ToString("MMMM dd"));
Console.WriteLine("Date in 'HH:mm:ss': " + d.ToString("HH:mm:ss"));

Convert String to DateTime

string dateString = "02/13/2021";
DateTime d;

DateTime.TryParse(dateString, out d); // parsing the string
Console.WriteLine("Parsed DateTime: "+d);

File Handling

File handling is C# is supported through the classes and methods in the System.IO namespace. Which allows us to read, write and append to files and also enable us to perform operations like moving, copying files, creating directories etc.

Following is the list of some of important classes in this namespace:

Classes Description
Path Operations on path information
File Access and manipulate files
Directory Access and manipulate a directory structure
DirectoryInfo Perform operations on directories
DriveInfo Information for the drives
FileInfo Perform operations on files
StreamReader Reading characters from a byte stream
StringReader Reading from a string buffer
BinaryReader Reads data from a binary stream
StreamWriter Writing characters to a stream
StringWriter Writing into a string buffer
BinaryWriter Writes data in binary to a stream
FileStream Read/Write data to a file
MemoryStream Access to streamed data stored in memory
BufferedStream Temporary storage for a stream of bytes

Let’s look into some of the operations which we can perform using these classes and the methods offered by them.

Creating a File

An empty file can be created using the System.IO.File.Create() method by passing the full path of the file as an argument. We can also test if the file already exists or not using the System.IO.File.Exists() method as shown in the following example:

using System;
using System.IO;

namespace FileHandling
{
    class Program
    {
        static void Main(string[] args)
        {
            string path = @"c:\temp\file.txt";
            File.Create(path); // create an empty file

            if(File.Exists(path)) // testing if file exists
            {
                Console.WriteLine($"File created successfully at \'{path}\'.");
            }
            else
            {
                Console.WriteLine($"File doesn't exists.");
            }
        }
    }
}

Deleting a File

A file can be deleted using the System.IO.File.Delete() method by simply passing the file path as an argument and if the file exists it will be deleted.

using System;
using System.IO;

namespace FileHandling
{
    class Program
    {
        static void Main(string[] args)
        {
            string path = @"c:\temp\file.txt";
            
            if(File.Exists(path)) // testing if file exists
            {
                File.Delete(path); // delete file
                Console.WriteLine($"File deleted successfully.");
            }
            else
            {
                Console.WriteLine($"File doesn't exists.");
            }
        }
    }
}

ReadWrite on a File

Reading a file is as simple as using the System.IO.File.ReadAllText() method with the file path and it will read the contents of a file. Similarly, writing to a file is achieved using the System.IO.File.WriteAllText() method as shown in the following example.

Please note that WriteAllText() method will rewrite the content of the file.

using System;
using System.IO;

namespace FileHandling
{
    class Program
    {
        static void Main(string[] args)
        {
            string path = @"c:\temp\file.txt";
            string data = "The quick brown fox jumps over the lazy dog"
            File.WriteAllText(path,data); // writing to a file
            Console.WriteLine(File.ReadAllText(path)); // reading from a file
        }
    }
}

Appending to a File

Often it is required to append a content to the bottom of a file, instead of rewriting it. In order to achieve that we use the in System.IO.File.AppendText() method to create a StreamWriter that appends text to an existing file or creates a new one if the file specified file doesn’t exist.

using System;
using System.IO;

namespace FileHandling
{
    class Program
    {
        static void Main(string[] args)
        {
            string path = @"c:\temp\file.txt";
            using (StreamWriter sw = File.AppendText(path))
            {
                sw.Write("\nAppending this to the file");
                sw.Close();
            }
        }
    }
}

Copy and Move a File

We have inbuilt methods to move and copy in the System.IO.File class, where we can pass source and destination file paths to perform the operation.

using System;
using System.IO;

namespace FileHandling
{
    class Program
    {
        static void Main(string[] args)
        {
            string path1 = @"c:\temp\file.txt";
            string path2 = @"d:\file.txt";
            File.Move(path1, path2); // moving the file
            File.Copy(path2, path1); // copying the file
        }
    }
}

Reading Recommendations