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.
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.
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.
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).
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.
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:
Compile Time - Transformation of source code to intermediate language.
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:
dotnetnewconsole--outputapp
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.
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.
dotnetrundotnetbuild
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
usingSystem;namespaceDemo{classClass1{Strings1="This is Class1";}classClass2{Strings1="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:
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:
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.
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#:
<NameOfClass>Object=new<NameOfClass>();
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#.
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#
usingSystem;publicclassHelloWorld{/* this is multi line comment that exist across multiple lines */staticvoidMain(string[]args){// this is a single-line comment Stringmessage="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
usingSystem;publicclassCase{staticvoidMain(string[]args){stringbook="Sapiens";stringBook="Mastery";stringBOOK="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
usingSystem;publicclassexample{staticvoidMain(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.ConsoleusingCon=System.Console;publicclassexample{staticvoidMain(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
usingSystem;// class has to implement IDisposable interfacepublicclassMessage:IDisposable{publicvoidPrint(){Console.WriteLine("Howdy!");}// dispose methodpublicvoidDispose(){Console.WriteLine("Dispose method called");}}publicclassexample{staticvoidMain(string[]args){using(Messagemsg=newMessage()){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:
Value types
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
publicclassexample{staticvoidMain(string[]args){// single variable declaration onlyboolflag;// multiple variable declaration onlyinta,b,c;// variable declaration and initializationdoublepi=3.14;charchr='a';intnum,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:
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
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
publicclassexample{staticvoidMain(string[]args){// simply writes the stringSystem.Console.Write("prints and stays on the same line");// writes the string followed by line terminatorSystem.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
publicclassexample{staticvoidMain(string[]args){System.Console.WriteLine("Enter Name");stringname=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:
Conditional Branching - if, if..else, switch
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
usingSystem;publicclassexample{staticvoidMain(string[]args){intx=5;if(x>3){// conditionConsole.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
usingSystem;publicclassexample{staticvoidMain(string[]args){intx=5;if(x>3){// conditionConsole.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
usingSystem;publicclassexample{staticvoidMain(string[]args){intx=9;if(x==0){// condition 1Console.WriteLine("x is equals to 0");}elseif(x>0&&x<=5){// condition 2Console.WriteLine("x is between 1 to 5");}elseif(x>5&&x<=10){// condition 3Console.WriteLine("x is between 5 to 10");}else{// if no conditions are metConsole.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
usingSystem;publicclassexample{staticvoidMain(string[]args){stringcity="Delhi";switch(city){// conditioncase"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.
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:
Try - Block of code which is tested or tried for errors
Catch - Block of code to handle the errors. There can be more than one catch blocks.
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
usingSystem;publicclassexample{staticvoidMain(string[]args){try{intx=1;inty=0;varresult=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.
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
usingSystem;publicclassexample{staticvoidMain(string[]args){try{intx=1;inty=0;varresult=x/y;Console.WriteLine($"Result: {result}");}catch(DivideByZeroExceptionexception){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
usingSystem;// class declarationpublicclassTable{// class propertiesintlength=300;intwidth=200;intheight=100;stringwoodType="Cedar";// class methodspublicvoidgetDetails(){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
usingSystem;publicclassexample{staticvoidMain(string[]args){// creating an object from 'Table' classTabletable1=newTable();// accessing method of the classtable1.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:
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
usingSystem;// class declarationpublicclassTable{// class propertiesintlength=300;intwidth=200;intheight=100;stringwoodType="Cedar";// class methodspublicvoidgetDetails(){Console.WriteLine($"Table is made of '{woodType}' wood");Console.WriteLine($"Dimensions are {length}x{width}x{height}cm");}}publicclassexample{staticvoidMain(string[]args){// creating an array of object from 'Table' classTable[]tables=newTable[5];// instantiating class and assigning object to array indextables[2]=newTable();// 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.
usingSystem;usingSystem.Linq;publicclassexample{staticvoidMain(string[]args){varintCollection=Enumerable.Range(0,5)// generate a collection of numbers from 0 to 4foreach(intnumberinintCollection){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.
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).
doublemyDouble=9.78;intmyInt=(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
usingSystem;publicclassexample{staticvoidMain(string[]args){// generate a range of numbers from 1 to 5varnumbers=Enumerable.Range(1,5);// see use of the expression lambda with the Select LINQ queryvarsquares=numbers.Select(x=>x*x);foreach(varsquareinsquares){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
usingSystem;usingSystem.Linq;publicclassexample{staticvoidMain(string[]args){// generate a range of numbers from 1 to 5varnumbers=Enumerable.Range(1,5);// define a statement lambda using the Func<T,T> delegateFunc<int,int>square=(x)=>{varvalue=x*x;returnvalue;};foreach(varnumberinnumbers){// use the statement lambda expressionConsole.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 characterSystem.Console.WriteLine("Hello world!\nThis is a new line");// printing column and rows with horizontal tab and new-lineSystem.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.
Concatenation is the process of appending one or more strings to the end of another string using the + operator.
stringname="John";// string concatenationsstringmsg="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:
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.
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 namesstringnames="Bill Gates,Oprah Winfrey,Jeff Bejos,Tom Cruise";// split string with a single charstring[]listOfNames=names.Split(',');foreach(stringnameinlistOfNames)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’.
stringoriginal="The quick brown fox jumps over the lazy dog";// Substring replacementvarmodified=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:
stringsentence=" 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.
stringbookName="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:
stringname="Bill Gates";// convert string array to char and printforeach(charchinname.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:
varchars=newchar[]{'b','i','l','l'};// convert char array to stringstringname=newstring(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.
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 DateTimestruct using the new keyword as shown in the following example:
DateTimed=newDateTime();// default value 01/01/0001 00:00:00// DateTime in specified year, month, day, hour, minute, and secondDateTimed=newDateTime(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 timeConsole.WriteLine(DateTime.UtcNow);// current date and time in UTCConsole.WriteLine(DateTime.Today);// today's date
TimeSpan
In C# a TimeSpanstruct 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 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:
vard=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
stringdateString="02/13/2021";DateTimed;DateTime.TryParse(dateString,outd);// parsing the stringConsole.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:
usingSystem;usingSystem.IO;namespaceFileHandling{classProgram{staticvoidMain(string[]args){stringpath=@"c:\temp\file.txt";File.Create(path);// create an empty fileif(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.
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.
usingSystem;usingSystem.IO;namespaceFileHandling{classProgram{staticvoidMain(string[]args){stringpath=@"c:\temp\file.txt";stringdata="The quick brown fox jumps over the lazy dog"File.WriteAllText(path,data);// writing to a fileConsole.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.
usingSystem;usingSystem.IO;namespaceFileHandling{classProgram{staticvoidMain(string[]args){stringpath=@"c:\temp\file.txt";using(StreamWritersw=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.
usingSystem;usingSystem.IO;namespaceFileHandling{classProgram{staticvoidMain(string[]args){stringpath1=@"c:\temp\file.txt";stringpath2=@"d:\file.txt";File.Move(path1,path2);// moving the fileFile.Copy(path2,path1);// copying the file}}}