C# - Learn C# FAST! The Ultimate Course Book (Beginners To Advanced) - Gary Mitnick

You might also like

Download as pdf or txt
Download as pdf or txt
You are on page 1of 242

C#:

Learn C# FAST!
The Ultimate Course Book (Beginners
to Advanced)

Gary Mitnick
© Copyright 2017. All rights reserved.

No part of this book may be reproduced or transmitted in any form or by any


means, electronic or mechanical, including photocopying, recording, or by any
information storage or retrieval system without prior written permission from
the author or copyright holder except in the case of brief quotations embodied
in reviews.

Although the author has exhaustively researched all sources to ensure the
accuracy and completeness of the information contained in this book, we
assume no responsibility for errors, inaccuracies, omissions, or any
inconsistency herein. Any slights of people or organizations are unintentional.
Reader should use their own judgment and/or consult a programming expert for
specific applications to their individual needs.
Table of Contents
Preface
Part I Introduction
What is C#?
What can I do with C#?
What is the .NET Framework?
Beginning C# programming with Visual Studio Community Edition
Namespaces
Coding Expressions and Statements
Keywords
C# Keywords
Variables
Types
Arithmetic Operators
Directing precedence
Associativity to evaluate expression
Associativity and the assignment operator
Incrementing and decrementing variables
Declaring implicitly typed local variables
Summary
Part II Understanding the C# Way
Methods and Properties
Declaring Methods
Returning data from a method
Calling methods
Applying scope
Local scope
Class scope
Method overloading
Optional parameters and named arguments
Passing named arguments
Handling uncertainties with optional parameters & named arguments
Decision statements and flow control
If statement
Cascading if statements
Code Blocks ({ })
Boolean variables
Boolean operators
Conditional logical operators
Short-circuiting
Null-coalescing operator(??)
Null-conditional operator(?.)
Control flow statements, continued
While & do/while loops
For loop
Foreach loop
Switch statement
Switch statement rules
Break statement
Exceptions and Error handling
Catching multiple exceptions
Throwing exceptions
System.ArguementException
System.ArguementNullException
System.ArguementOutOfRangeException
System.InvalidOperationException
System.NotSupportedException
System.NotImplementedExcepetion
System.ObjectDisposedException
Classes and objects
Encapsulation
Declaring a class
Controlling accessibility
Creating an object
Constructors
Static Classes
Value types and Reference types
Value types
Reference types
Copying value & reference types
Null values
Nullable types
The System.Object class
Boxing
Unboxing
Casting data safely
The is operator
The as operator
Enumerations
Structures
Differences between structures and classes
Arrays
Declaring array variables
Creating an array instance
Populating and using an array
Creating an implicitly typed array
Accessing an individual array element
Iterating through an array
Using multidimensional arrays
Parameter arrays
Inheritance
Base class constructors
Virtual methods
Override methods
Protected access
Extension methods
Interfaces
Defining an interface
Implementing an interface
Referencing a class through its interface
Multiple interfaces
Explicitly implementing an interface
Interface restrictions
Abstract classes
Abstract methods
Sealed classes
Sealed methods
Garbage collection
Object lifetime
Writing destructors
Why use the garbage collector?
How the garbage collector works
Recommendations
Resource management
Disposal methods
Exception-safe disposal
Using and IDisposable interface
Calling the Dispose method from a destructor
Features of the IDispose class:
Part III Extending C# Types
Properties
Using properties
Read only properties
Write-only properties
Property accessibility
Property restrictions
Indexers
An example which doesn’t use indexers
The same example using indexers
Understanding indexer accessors
Comparing indexers and arrays
Indexers in interfaces
Generics
C# without generics
C# with generics
Collections
The List<T> collection class
The LinkedList<T> collection class
The Queue<T> collection class
The Stack<T> collection class
The Dictionary<TKey, TValue> collection class
The SortedList<TKey, TValue> collection class
The HashSet<T> collection class
Using collection initializers
The Find methods, predicates, and lambda expressions
Delegates
Declaring a delegate
Lambda expressions
Lambda expressions forms
Events
Declaring an event
Subscribing to an event
Unsubscribing from an event
Raising an event
LINQ
Fundamentals
Simple Query
Projecting data
Grouping, ordering and aggregating data
Joining data
References
MSDN C# Programming guide (Guide on key C# language features):
Visual Studio Developer Essentials (some great resources!):
Stack overflow (when your program doesn’t work!):
101 LINQ samples (examples you can use in your programs):
Preface
This Ebook is aimed at anyone wanting to learn the C# programming language
but is not completely new to programming.
The first section of this Ebook introduces you to the basics of C#. Should you
not have a software installed to develop C# applications, you can get Visual
Studio installed and have a simple console application up and running in no
time. A basic introduction to keywords, namespace types and arithmetic
operators is covered which is built on in the next section.
The second part of this Ebook takes these simple operations and places them
into methods and explains how to make decision in your program, set up a path
of execution and deal with errors. It covers how values are stored in computer
memory and why it is important for your program. Classes, objects and
encapsulation show you how to model entities in your code while
enumerations and arrays means of storing and manipulating your data.
The third section of this Ebook you will learn how to extend the types you have
created in the second part of this book. You will learn about creating events
that other sections of the program can listen to and take action on via
delegates. Learn about LINQ - a powerful tool for any developer working
with data. Use Lambda expression to create local functions and create
delegates.
The key to learning C# is to start coding as soon as possible. Don’t wait until
you an expert in theory – start writing software immediately.
I hope you will find this Ebook to be a great resource in establishing your C#
expertise and you will continue to reference it. I have placed some references
at the very back of this Ebook, that I hope you will find very useful.
Part I Introduction
What is C#?
C# is a multi-paradigm (or multi styled) object-oriented programming (OOP)
language encompassing strong typing (argument must match type), declarative
(describe what you wish to do and not how you want to do it), imperative
(how to do), functional (functional approach), generic (algorithms are
developed in terms of types to be detailed later) and also component oriented
programming (i.e. an internet service, a software package, a web site resource
or perhaps a component which encapsulates some related features or
information.
The aim is to allow programmers to use the most suitable programming style
and associated language constructs for a specified job, seeing that not one
example solves all problems.
Microsoft C# is now a well-established programming language that builds on
features found in predecessor C-style languages (like C, C++ and Java) making
it acquainted to many knowledgeable programmers. It inherits lots of the best
highlights of C++ yet is designed to be a cleaner and more logical language.
C# is part of a larger, more complex open source execution platform called the
Common Language Infrastructure (CLI). It is this specification that facilitates
us to use a high-level language like C# on various machines (Mac OS X,
Linux, Solaris, iOS, Android) without rewriting the code.
Common Language Infastructure (CLI)

C# Code VB.Net Code J# Code

Compiler Compiler Compiler

Common Language Infastructure

Common
Intermediate
Language.

Common
Language
RunTime.
1010101010101010101010101010101010101
Instead of directly generating instructions which a processor can understand,
the C# compiler issues instructions in an intermediate language, the CIL
(Common Intermediate Language). An additional compilation step occurs,
usually at execution time, converting the CIL to machine code that the
processor can understand.

What can I do with C#?


With C#, you can develop web applications with ASP.NET, build mobile
applications with Windows Phone desktop or develop applications with
Windows Presentation Foundation (WPF). Some other applications consist of
code which runs in the cloud via iOS, Windows Azure, Android and Windows
Phone support the Xamarin platform.
What is the .NET Framework?
.NET is a platform which incorporates languages, a runtime, and framework
libraries, enabling developers to create numerous types of applications. C# is
one of the main .NET languages, however there is Visual Basic, F#, C++, and
more.

VB.Net C# JScript .Net


Languages

Common Language Specification (CLS)


Common Type System (CTS)
.NET Framework Class Library (FCL)
ASP.NET (Web Forms, XML Web Services), Windows
Forms, Console

ADO.NET .NET Remoting


Common Language Runtime
[ J.I.T Just In Time Compilers, Security Manager, Garbage
Collector]

Common Language Infrastructure (CLI)


Operating System

The formal name of the runtime is the CLR or Common Language Runtime.
The programming languages that aim at the CLR compile into an Intermediate
Language (IL). The CLR itself can be described as virtual machine that runs IL
and supplies many offerings such as memory management, security, exception
management, garbage collection and much more.
The FCL or Framework Class Library is a set of reusable code that offers both
technology-specific platforms and general all-purpose services. The general
services include crucial types such as networking, cryptography, collections,
and more. In addition to general classes, the FCL contains technology-specific
platforms like WPF, web services, ASP.NET amongst others. The FCL worth
comes from having common components available for reuse, conserving time
and money without needing to write that code by yourself.
There’s an enormous ecosystem of open-source and commercial software that
depend on and supports .NET. You must visit GitHub, CodePlex or any extra
open-source code repository site and see the many projects written in C#.
Commercial offerings include services and tools to assist you building code,
manage systems, and offer applications.
Beginning C# programming with
Visual Studio Community Edition
The previous section described numerous great things you can do with C#,
however most of them are so detailed that they need their own book. This
Ebook is totally focused on the C# programming language and the code will be
executed as a console application. It’s the simplest application to get up and
running and once you comprehend the code you can easily use it on another C#
application type. You can write your code with any editor, but this Ebook uses
Visual Studio 2015 Community Edition which is free.
Should you not have Visual Studio installed on your machine, please visit the
following address: https://www.visualstudio.com/downloads/ and select Free
download of Microsoft Visual Studio Community Edition.
Once Visual Studio is downloaded, follow the installation through and start VS
up. In VS, select File > New > Project, then select Installed > Templates >
Visual C# in the tree on the left, and finally select the Console Application
project type. In the Name field rename it to HelloWorld.
Set the location to your preference, and click OK. This will create a new
solution for you. When Visual Studio finishes loading, your solution will
appear. Add the following line Console.WriteLine("Hello World"); as
illustrated:
using System;
namespace HelloWorldNamespace
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World");
}
}
}

Once complete Press Control and F5. Or go to the Menu select Debug and
Start Without Debugging. If you just press F5 VS will run the program with
waiting for a response. This will compile your program and print the
following on the console:
Hello World
Press any key to continue...
The Program.cs file outlines a class named Program which has a Main
method. In C#, all executable code must be defined within a method, and all
methods must belong to a class or a struct.
The Main method designates the program’s entry point. This method should be
defined in the manner specified here in the Program class, as a static method; If
it’s not designated as such the .NET Framework might not recognize it as the
starting point for your application when you run it.
Note: C# is a case-sensitive language. You must spell Main with an
uppercase M.
A class has members and this example shows a method member named Main.
A method can be equated to a function or a procedure in other programming
languages. There are two sets of curly braces, one for the Program class and
another for the Main method which are referred to as a block, indicating the
beginning and end of scope.
The static modifier indicates that there is only ever one instance of a Program
class that has that Main method — it is the static instance. Main must be static,
but other methods can omit static, which makes them instance members. This
means that you can have numerous copies of a class or instance with their own
method.
Seeing that a program only needs a single Main method, static makes sense. A
program that manages clients might have a Customer class and you would need
several instances to represent each Customer. Later you will see examples of
instantiating classes later in this Ebook.
The code begins with a using clause for the System namespace. Typically, the
FCL (Framework Class Library) is gathered into namespaces to keep code
organized and prevent clashes involving identically named types. This using
clause enables us to utilise the code in the System namespace. We are doing so
with the Console class. Without that namespace, the compiler doesn’t know
what Console means or how to find it, however now C# knows that we’re
using the System.Console class.
Namespaces
The actual example up to now have been an extremely application. However,
little programs may grow in too much larger programs. And as a program
develops, two problems arise. Firstly, it is more difficult to comprehend and
maintain large programs than it is to comprehend and maintain small programs.
Secondly, extra code usually means extra classes, with more methods,
requiring you to keep tabs on more names. One of the most convenient and
simplest ways to organize code is with the C# namespace feature. The
following is a hierarchical portrayal of where namespaces fit into a program
overall structure:
Namespace
Type
Type Members
Out of this hierarchy, the namespace is optional, however if you leave it out the
class will be a member of the global namespace so the there is a possibility of
a clash with other class names. It’s a rather good procedure to place each of
your classes in namespaces. You are able to bring the namespace in to scope
using the using directive at the top of the program.
Coding Expressions and Statements
In the first part of this Ebook you saw how to write compile and execute a
simple C# Program. The example program had a single statement in the Main
method. Now you will learn how to write more statements and add logic to
your program.
Whitespace: C# is a “free format” language, which means that white space
(space, tab and newline characters) is not significant except as a separator.
So, you are free to lay your statements in any style you choose.
Keywords
To allow the compiler to translate the program code, certain terms within C#
have unique status as well as meaning. These are known as keywords, and they
deliver the concrete syntax that the compiler utilises to interpret the
expressions that the programmer writes. In the first HelloWorld program,
class, static, and void are all instances of keywords.
The compiler utilises the keywords to identify the organization and structure of
the code. Since the compiler interprets these words with higher significance,
C# necessitates that developers place keywords only in certain locations.
When your program break these rules, the compiler will promulgate errors.

C# Keywords
abstract as base bool
break byte class catch
checked char case const
continue decimal default delegate
do double else enum
event explicit extern false
finally fixed float for
foreach goto if implicit
in int in Interface
internal is long lock
namespace new null object
operator out out override
params private protected public
readonly ref return sbyte
sealed sizeof short stackalloc
string static struct switch
this throw try true

In addition, C# also uses the subsequent identifiers. However, these identifiers


are not reserved in C# so you can use these names as identifiers for your own
variables, methods, and classes but nevertheless the best action to take is to
stay away from doing so whenever feasible
alias Add ascending
async await descending
dynamic from get
group global into
join let orderby
partial (type) partial (method) remove
select set value
var where where (generic)
yield
Variables
What is a variable? It is simply a storage area or container with a name which
our programs can change its contents. Every variable in C# has a particular
type, which governs size and layout of the variables memory, the variety of
values that can be stored within that memory and the list of operations that is
applied to the actual variable.
You must give your variables a well understood name and make sure don’t use
the keywords (previous section). There is a standard naming convention in C#
meaning you cannot start variable names with an ‘_’ underscore. It's really
advisable to follow best practice of placing a lowercase letter with each
subsequent word of the variable having an initial uppercase letter. (This is
camelCase).
Variables hold values and C# has many dissimilar types of values that it can
store and process, for example: floating-points numbers, integers and strings of
characters. Whenever you declare a variable, you must specify the type of data
it will hold.
Types
A type sets out the blueprint for a value. As discussed C# is a strongly typed
language, which means that the compiler won’t implicitly convert between
incompatible types. For instance, you can’t assign a string to an integer or an
integer into a string (certainly not implicitly) The subsequent code example
will not compile:
int total = “359”;
string message = 7;
The following tables illustrates the built-in types:

Type (inc. Literal Suffix) Description


Values/Range
byte 8-bit unsigned integer 0 to 255
short 16-bit signed integer -32,768 to 32,767
sbyte 8-bit signed integer -128 to 127
ushort 16-bit unsigned integer 0 to 65,535
int 32-bit signed integer -2,147,483,648 to
2,147,483,647
uint 32-bit unsigned integer 0 to 4,294,967,295
long (l) 64-bit signed integer 9,223,372,036,854,775,808 to
the value of
9,223,372,036,854,775,807; that is, hexadecimal x7FFFFFFFFFFFFFFF.

You should add a suffix to a number when the meaning would be ambiguous.
With the subsequent example the m suffix ensures that the 6.25 is handled as a
decimal number:
decimal price = 6.25m;
You can assign Unicode values direct to any char. The following demonstrates
how to delegate a space to a variable named addASpace
char addASpace = '\u0032';

Also, you can get the Unicode value of a character by performing a cast
opertation:

int spaceUnicode = (int)space;


Arithmetic Operators

C# supports regular arithmetic operations like the plus sign (+) for addition,
the minus sign (-) for subtraction, the asterisk (*) for multiplication and the
forward slash (/) for division. The symbols +,-,*, and / are called operators
since they operate on value to create new -values. In the following example,
the variable priceGain ends up holding the product of 1250 and 3:

Long priceGain;
priceGain = 1250 * 3;

C# has many other operators that allow you to perform all of the logical
operations you would expect of any general-purpose programming language.
The subsequent table illustrates some of the available operators:

Category Description
Primary x.y x?.y f(x) a[x] x—x++ new typeof
default unchecked checked nameof
Unary + - ! ~ ++x --x (T)x await x
Multiplicative */ %
Additive +-
Shifting << >>
Type and Relational Testing <=, >=, < >,is, as
Equality == !=
Logical AND &
Logical XOR ^
Logical OR |
Conditional AND &&
Conditional OR ||
Null Coalescing ??
Conditional ?:
Assignment = *= /= %= += -= <<= >>= &= ^= |= =>

Prefix operators change the value of the variable before assignment, and
postfix operators modify a variable after assignment, as illustrated in the
following example:
int value1 = 6;
int value2 = ++val1;
int value3 = 3;
int value4 = val3--;
Both value1 and value2 are 7. The value3 variable is 2, but value4 is 3. This
is so because the postfix operator evaluates after assignment.
Directing precedence
Priority is given to some operators over others. Consider the following
expression, which uses the + and * operators:
2+3*5
This expression is potentially vague, but In C#, the multiplicative operators (*,
/, and %) have precedence over the additive operators (+ and –). In this
example, the 3 * 5 multiplication is executed first followed by the + 2
addition. The answer to 2 + 3 * 5 is therefore 17.
You can use parentheses () to override precedence and force operands to bind
to operators in a way of your choosing. For example, perform the addition of 2
and 3 and multiply the result by 5:
(2 + 3) * 5
Associativity to evaluate expression
Sometimes an expression contains different operators that have the same
precedence, like / and *. Associativity is the direction (left or right) in which
the operands of an operator are assessed. Look at the following expression
that uses the * and / operators:
4/ 2*7
In this instance, the associativity of the operators governs how the expression
is assessed. The two multiplicative operators * and / are left-associative,
denoting that the operands are assessed - left to right. In this case, 4/2 will be
assessed before multiplying by 7, giving the result 14.
Associativity and the assignment operator
As noted the equal sign (=) is an operator. Each operator returns a value based
on their operands and the same goes for the = assignment operator. It acquires
left hand side and right hand side operands. It simply takes the right side,
evaluates it, and stores it on the left side. The left operand has the value of the
assigned operator. In the subsequent example the value returned by the
assignment operator equals 15:
int myInteger;
myInteger = 15; // The value of assignment expression is 15
Equally you can assign several variables to the same value:
myInteger 5 = myInteger 4 = myInteger 3 = myInteger 2 = myInteger = 15;
Incrementing and decrementing variables
In C#, you can use the + operator to increment a variable, as demonstrated
here:
initialPrice = initialPrice + 1;
However, this is so common in C# that it has its own operator:
initialPrice++;
Equally, the subsequent code subtracts 1 from the variable initialPrice:
initialPrice--;
You can place the ++ or – on either side of the variable but take note that all
operators are utilised to evaluate an expression that has a value. So the value
returned by initialPrice ++ is the value of count before the increment takes
place, whereas the value returned by ++ initialPrice is the value of count after
the increment takes place. Here is an example:
int initialPrice;
initialPrice = 35;
Console.WriteLine(initialPrice++); // initialPrice is now 36, 35 is outputted to
console
initialPrice = 35;
Console.WriteLine(initialPrice++); // initialPrice is now 35, 35 is outputted to
console
Declaring implicitly typed local variables
So far in this Ebook you have saw that you declare a variable by specifying a
data type and an identifier, like the following:
int myInt;
It is also good practice to assign a value before you attempt to use it. Like the
following:
int myInt = 100;
You must remember that the value you assign must be of the same type as the
variable. The compiler can work out which is the best type of expression if
you use the var expression as demonstrated in the subsequent example:
var myFirstVariable = 1000;
var mySecondVariable =”Bonjour!”;
In the subsequent examples, myFirstVariable is an integer, and
mySecondVariable is a string. It is most important however, for you to
appreciate that this is a handiness for declaring only variables, and after a
variable has been declared you can assign only values of that type to it. You
can’t for example, assign a double, float or string values to myFirstVariable at
a later point in your code. You should take note that you can only utilise the var
keyword once you have supplied an expression to initialize a variable. This
subsequent declaration is illegal and the program will not compile:
var OneMoreVariable; // compiler can’t determine the type - Error
Summary
In this section, you saw how to create a simple C# program, how to use
variables, you learnt about the common data types available for variables in
C#. You also learnt about the precedence & associativity of operators and
how expressions are assessed.
Part II Understanding the C# Way
Methods and Properties
The previous chapters shown how to write code in the Main method. That’s
the programs entry point but its normally a lightweight method without too
much code. In this chapter, you will begin to relocate your code out of the
entry point of the program to better manage your code. You will start how to
outline methods with parameters and return values. You will also utilise
properties, which in turn lets you encapsulate the object state.
A method is a grouping together a series of statements to accomplish a
particular action or compute a certain final result. It is a named series of
statements. In other languages, like C, C++ or Visual Basic you can see a
method is similar to a function or subroutine. It has a name and a body. The
method name should be a meaningful identifier that indicates the overall
purpose of the method (for example, calculateTakeHomePay). The lines of
code to be executed are included in the body of the method. Those lines are
executed when the method is called. The method can be given some data for
processing and can return information, which is typically the result of the
processing. In C# methods are a fundamental and powerful mechanism.
Declaring Methods
The syntax for declaring a C# method is as follows:
returnType methodName ( parameterList )
{
// method body statements go here
}
The returnType is the name of a type and specifies what kind of information the
method returns as an outcome of the methods processing. This can be any type
(a list is given in the previous chapter) such as an int or string. If it failes to
return anything then you must utilise the keyword void in place of the return
type.
The methodName is the name used to call the method. You should follow the
same camelCase convention as used when declaring variables earlier, for
example calculateTakeHomePay.
The parameterList is not mandatory but it describes the names and types of the
information that you can pass into the method for it to process. You write the
parameters between opening and closing parenthesis ( ) like you are declaring
a variable with the name of the type succeded by the name of the parameter for
example, (int firstParameter, int SecondParameter). If the method takes
more than one parameter, you must separate each value with a comma.
The statements in the method body are the lines of code that are executed when
the method is invoked. They are surrounded by opening and closing braces
{}.
Returning data from a method
If you wish to return data from a method, you must include a return statement at
the end of processing in the main body of the method. The return statement can
contain two parts, the word return suceeded by an expression that indicates the
return value, and a semicolon. The type of the expression must be the same as
the type specified by the method declaration. Therefore, if a method returns an
integer, the return statement has to return an int; or else, your program simply
will not compile.
The subsequent an example of a method named addTwoNumbers which takes
two integer values as parameters, add the values together and returns an int
value:
int addTwoNumbers(int firstNumber, int secondNumber)
{
return firstNumber + secondNumber;
}

If you don’t want your method to return anything from your method you can use
return followed by a semicolon like the following, it will immediately exit the
method:
{
return;
}
Calling methods
You can call a method from another part of the program to perform its task. In
order to call the method, you must use its exact name and match its signature as
specified by its parameters. So, if a method has two integer parameters you
must pass two integer values. Using the above addTwoNumbers example the
following is fine:
addTwoNumbers(23, 6);
You can replace the numeric values of 23 and 6 with the names of two int
values and then call the method like so:
int num1 = 23;
int num2 = 6;
addTwoNumbers(num1, num2);
Applying scope
The scope of a variable is the region of the program in that that variable is
actually usable. A variable is said to be in scope in a particular location when
it can be accessed at that location in a program. You are able to specify
variables with diverse scope. Scope is applicable to methods in addition to
variables. The actual scope of an identifier (be it variable or method) is
associated to the location of the declaration that introduces the identifier in the
program
Local scope
The actual opening and closing brackets that make the body of a method define
scope of a method. Every variable which you declare inside the body of a
method is scoped to that method; they vanish when the method ends and can be
accessed solely by code running in that method. They are known as local
variables for the reason that they are local to the method in which they are
declared; they are not in scope in any additional method.
It is not possible to share information between methods because of the scope of
local variables. Consider the following example:

class Example
{
void firstMethod()
{
int myVar;
}
void anotherMethod()
{
myVariable = 42; // error - variable is not in scope
}
}

The specific code will not compile due to the fact anotherMethod is
attempting to utilize the variable myVar, which isn't in the same scope. myVar
the variable, is available solely to the code in firstMethod - between the two
braces.
Class scope
The {opening and closing} braces which form the main body of a class
determine the scope of the class. Whatever variable you declare in the body of
a class (excluding any variables in a method) are scoped to that class. The
proper C# term for a variable defined by a class is field. As previously stated,
you can utilise fields, as opposed to local variables, to share information
between methods. For instance:
class Example
{
void firstMethod()
{
firstField = 78; // This is fine
}
void anotherMethod()
{
firstField++; // This is fine
}
int firstField = 3;
}

The variable firstField is defined outside the methods firstMethod and


anotherMethod in the class. Therefore, firstField has class scope and is
accessible for use by every method in that class.
There is one other point to notice about this example. Inside a method, you
must declare a variable before you can avail of it. However, fields are a bit
different. A method can utilise a field before the statement that actually defines
the field. The compiler works out the details.
Method overloading
Essentially, overloading a method is when you have numerous methods with
identical names but take different parameters. Different parameters could be
varying the parameter count and/or varying data types.
Method overloading is a form of polymorphism. Polymorphism occurs when
the same logical operation takes on my (“poly”) forms (“morphs”) because the
data varies.
Overloading is most useful when you need to carry out the exact same
operation on different data types or different groups of information. Keep in
mind that even though it is possible to overload the parameters of a method,
you can’t overload the return type of a method i.e. you can’t have two methods
with identical names with the only different is their return type.
The following is an example of overloading a method. Here you can see a
class call IntroductoryMaths, it has three methods with the same name but take
a different number of parameters.

class IntroductoryMaths
{
public static int Addition(int numero1, int numero2)
{
return Addition(numero1, numero2, 0);
}
public static int Addition(int numero1, int numero2, int numero3)
{
return Addition(numero1, numero2, numero3, 0);
}
public static int Addition(int numero1, int numero2, int numero3, int numero4)
{
return numero1 + numero2 + numero3 + numero4;
}
}
Optional parameters and named arguments
Starting with C# 4.0, the language designers added support for optional
parameters. By allowing the association of a parameter with a constant value
as part of the method declaration, it is possible to call a method without
passing an argument for every parameter of the method.
A key feature of C# and other languages designed for the .NET Framework is
the capability to interoperate with applications and components written by
using other technologies. One of the principal technologies that underpins
many Microsoft Windows applications and services running outside of the
.NET Framework is the COM or Component Object Model. It does not
support overloaded methods; rather, it utilises methods that can take optional
parameters.
In this method, the first parameter is mandatory because it does not stipulate a
default value, but the second and third parameters aren’t required:

void optionalMethod(int first, double second = 0.0, string third =


"Bonjour!")
{
...
}

You must specify all compulsory parameters before any non-compulsory ones.
You can call up a method in which takes non-compulsory parameters in the
same way that you call any other method i.e. specify method name and any
required arguments. The distinction of methods that take optional parameters
is that you can leave out the corresponding arguments - the method uses the
standard value when it runs.
In the subsequent example, the first call to the optionalMethod method
provides values for all three parameters. The second call stipulates only two
arguments, and these values are applied to the first and second parameters. The
third parameter receives the default value of “Bonjour” when the method runs.
optionalMethod(99, 123.45, “le Monde!”); // All three parameters have
arguments provided
optionalMethod(333, 54.456); // Arguments provided for first two parameters
only
Passing named arguments
A second method call feature made available in C# 4.0 is the use of named
arguments. With named arguments, it is possible for the caller to explicitly
identify the name of the parameter to be assigned a value, rather than relying on
parameter and argument order to correlate them. To pass an argument as a
named parameter, you specify the name of the parameter, followed by a colon
and the value to use. The subsequent examples perform the same function as
those in the previous section, except that the parameters are specified by name:
optionalMethod (first : 99, second : 123.45, third : “le Monde!”);
optionalMethod (first : 333, second : 54.456);
Handling uncertainties with optional parameters &
named arguments
Using optional parameters and named arguments can result in some possible
ambiguities in your code. You must understand how the compiler resolves
these ambiguities; otherwise, you might find your applications behaving in
unexpected ways. Suppose that you define the optMethod method as an
overloaded method, as shown in the subsequent example:
void optionalMethod(int first, double second = 0.0, string third = "Bonjour")
{
...
}
void optionalMethod(int first, double second = 1.0, string third = "Au Revoir", int
fourth = 100)
{
...
}

This is perfectly legal C# code that follows the rules for overloaded methods.
The C# compiler can tell the difference between the methods as they take
different parameter lists. However, as demonstrated in the following example,
a problem can arise if you attempt to call the optionalMethod method and omit
some of the arguments corresponding to one or more of the optional
parameters:
optionalMethod (1, 2.5, “le Monde”);
Again, this is perfectly legal code, but which version of the optionalMethod
method does it run? The answer is that it runs the version that most closely
matches the method call, so it invokes the method that takes three parameters
and not the version that takes four.
optionalMethod (1, fourth : 101);
In the above code, the call to optionalMethod omits arguments for the second
and third parameters, but it specifies the fourth parameter by name. Only one
version of optionalMethod matches this call, so this is not a problem.
optionalMethod (1, 2.5);
This time, neither version of the optionalMethod method exactly matches the
list of arguments provided. Both versions of the optionalMethod method have
optional parameters for the second, third, and fourth arguments. So, does this
statement call the version of optionalMethod that takes three parameters and
use the default value for the third parameter, or does it call the version of
optionalMethod that takes four parameters and use the default value for the
third and fourth parameters? The answer is that it does neither. This is an
unresolvable ambiguity, and the compiler does not let you compile the
application. The same situation arises with the same result if you try to call the
optionalMethod method as shown in any of the subsequent statements:
optionalMethod (1, third : “le Monde”);
optMethod(1); optMethod(second : 2.5, first : 1);
Decision statements and flow control
To solve real world problems, you need the capability of your code to
selectively perform different actions.
You can perform this task with flow control statements which provide the
means for conditional logic within a program or looping over a section of code
numerous times. Even a simple program cannot be written in C# without using
flow control statements. This first section discusses how to change the order
of statement execution based on conditional checks, then you will learn how to
execute statement groups repeatedly by constructing loop.
If statement
The if statement is one of the most common statements in C#. It assesses a
Boolean expression (an expression that returns true or false, see below) called
the condition. If the condition is true, the next statement is executed. An if
statement can contain an optional else clause that contains an alternate
statement to be executed if the condition is false. The general form is as
follows:
if (condition)
consequence-statement
else
alternative-statement
In the example that follows, Answer1 appears if both zee > 10 and zed > 20
evaluate to true. If zee > 10 is true but zed > 20 is false, Answer2 appears.
// Try with zee = 12 and then with zed = 18.
int zee = 12;
int zed = 18;
if (zee > 10)
if (zed > 20)
{
Console.WriteLine("Answer1");
}
else
{
Console.WriteLine("Answer2");
}
Cascading if statements
It is possible to nest if statements inside other if swhich cntatements. By doing
so you can chain together a sequence of Boolean expressions, which are tested
one after another until one of them are true. In the subsequent example, if the
value of todaysDay is 0, the first test evaluates to true and dayOfWeek is
assigned the string “Sunday”. If the value of todaysDay is not 0, the first test
fails and control passes to the else clause, which runs the second if statement
and compares the value of todaysDay with 1. The second if statement executes
only if the first test comes back false. Likewise, the third if statement executes
only if the first and second test returns false.

int todaysDay = 0;
string dayOfWeek = "";

if (todaysDay == 0)
{
dayOfWeek = "Sunday";
}
else if (todaysDay == 1)
{
dayOfWeek = "Monday";
}
else if (todaysDay == 2)
{
dayOfWeek = "Tuesday";
}
else if (todaysDay == 3)
{
dayOfWeek = "Wednesday";
}
else if (todaysDay == 4)
{
dayOfWeek = "Thursday";
}
else if (todaysDay == 5)
{
dayOfWeek = "Friday";
}
else if (todaysDay == 6)
{
dayOfWeek = "Saturday";
}
else
{
dayOfWeek = "Invalid";
}
Code Blocks ({ })
By utilizing curly braces, we can synthesise statements into one statement
termed a block statement or code block. It allows the grouping of many
statements into a single statement which is the consequence. In the subsequent
example, two statements that reset the sec variable to 0 and increment the min
variable are grouped inside a block, and the entire block executes if the value
of sec is equal to 59:
int sec = 0;
int min = 0;

if (sec == 59)
{
sec = 0;
min++;
}
else
{
sec++;
}
Boolean variables
C# offers a data type called bool. It holds either true or false. The subsequent
statements declare a bool variable called areYouReady and assign true to it.
True is then outputted to the console:
bool areYouReady;
areYouReady = true;
Console.WriteLine(areYouReady); // Outputs True on the console
Boolean operators
C# has several very useful Boolean operators (an operator that returns true or
false). The simplest is the NOT operator, it is represented by the ! exclamation
point. If the statement areYouReady is true, then !areYouReady is false (i.e. the
opposite of that value).
The two most common used Boolean operators are equality (==) and
inequality (!=). These are binary operators with which you can ascertain if
one value is the same as another value of the same type, returning a Boolean
answer.
Operator Meaning Example Outcome if
age is 42
== Equal to age == 100 false
!= Not equal to age != 0 true

The equality operator == with the assignment operator = are not the same! The
expression a==b compares a with b and has the value true if the values are the
same. The expression a=b assigns the value of b to a and returns the value of b
as its result.
The relational operators are closely related to == and !=. You use these
operators to find out whether a value is less than or greater than another value
of the same type. The subsequent table shows how to use these operators.
Operator Meaning Example Outcome if
age is 42
< Less than age < 21 false
<= Less than
or equal to age <= 18 false
> Greater than age > 16 true
>= Greater than
or equal to age >= 30 true
Conditional logical operators
C# also provides two other binary Boolean operators: the logical AND
operator, which is represented by the && symbol, and the logical OR operator,
which is represented by the || symbol. Together, these are known as the
conditional logical operators. Their function is to unite two Boolean
expressions or values into a single Boolean result. These operators are similar
to the equality and relational operators in that the value of the expressions in
which they appear is either true or false, but they differ in that the values on
which they operate must also be either true or false.
The outcome of the && operator is true if and only if both of the Boolean
expressions it’s evaluating are true. In the subsequent statement the value true
is assigned to validPercentage on the criteria that the value of percentage is
greater or equal to 0 and the value of percentage is less than or equal to 100:
bool validPercentage;
validPercentage = (percentage >= 0) && (percentage <= 100);
The result of the || operator is true if any of the two Boolean expressions it
evaluates is true. You can utilize the || operator to work out if any one in a
series of Boolean expressions is true. In the subsequent statement the value
true is assigned to invalidPercentage on the criteria that the value of
percentage is less than 0 or the value of percentage is greater than 100:
bool invalidPercentage;
invalidPercentage = (percentage < 0) || (percentage > 100);
Short-circuiting
The && and || operators both exhibit a feature called short-circuiting. There
are occasions that it is not necessary to evaluate both operands when
ascertaining the result of a conditional logical expression. For example, if the
left operand of the && operator evaluates to false, the result of the entire
expression must be false, regardless of the value of the right operand.
Similarly, if the value of the left operand of the || operator evaluates to true, the
result of the entire expression must be true, irrespective of the value of the
right operand. In these instances, the && and || operators bypass the evaluation
of the right operand. Here are some examples:
(percentage >= 0) && (percentage <= 100)
In this expression, if the value of percentage is less than 0, the Boolean
expression on the left side of && evaluates to false. This value means that the
result of the entire expression must be false, and the Boolean expression to the
right of the && operator is not assessed.
(percentage < 0) || (percentage > 100)
In this expression, if the value of percentage is less than 0, the Boolean
expression on the left side of || evaluates to true. This value means that the
result of the entire expression must be true and the Boolean expression to the
right of the || operator is not assessed.
If you cautiously design expressions that use the conditional logical operators,
you can enhance the performance of your code by sidestepping needless work.
In order to do this just put the Boolean expressions that can be easily worked
out on the left side of a conditional logical operator, and put the more complex
expressions on the right side. In numerous cases, you will discover that the
program doesn’t need to work out the more complex expressions.
Null-coalescing operator(??)
It is a short way of saying “If this value is null, then use this other value.” It
has the following form:
expression1 ?? expression2
The null-coalescing operator also uses a form of short-circuiting. If
expression1 is not null, its value is the result of the operation and the other
expression isn’t assessed. If expression1 does equate to null, then whatever
value is in expression2 is the result of the operator. The null-coalescing
operator is a binary operator.
Null-conditional operator(?.)
Whenever you invoke a method on a value that is null, the runtime will throw a
System.NullReferenceException error. This is an exception that almost
always indicates an error in the programming logic because the developer
didn’t perform sufficient null checking before invoking a member on a (null)
object.
In recognition of the frequency of the frequency of this pattern (that is, checking
for null before invoking a member), C# 6.0 introduces the “.?” Operator,
known as the null-conditional operator. Here are some examples:
int? length = consumer?.Length; // returns null if consumer is null
Consumer first = consumer?[0]; // returns null if consumer is null
int? count = consumer?[0]?.Orders?.Count(); // null if consumer, first
consumer, or Orders is null
Control flow statements, continued
Now that we’ve described Boolean expressions in more detail, we can cover
in more details flow control statements which C# supports.
While & do/while loops
To date you have seen how to create programs that perform a task only once.
However, computers can effortlessly perform similar operations multiple
times. In order to carry this out, you must create an instruction loop, since it is
the simplest conditional loop. The general form of the while statement is as
follows:
while ( booleanExpression)
statement
The Boolean expression (which must be enclosed in parentheses) is assessed,
if true, the statement is executes and the Boolean expression is assessed once
again. If still true, the statement is repeated and then the Boolean expression is
assessed once more. This procedure lasts until the Boolean expression
evaluates to false and the while statement exits.
int l = 10;
while (l > 0)
{
Console.Write(l);
l--;
}
The following is a while statement that writes the values 10 through to 1 on
console. Note that as soon as the variable I reaches the value 1, the while
statement finishes

The following is outputted to the console: 10,9,8,7,6,5,4,3,2,1


The do/while loop is very akin to the while loop however a do/while loop is
favoured when the number of repetitions is from 1 to n and n is unknown when
iterating commences. This pattern often occurs when asking input from a user.
For loop
This loop iterates over a block of code until a stated condition is reached. It is
very like the while loop. The distinction is that the for loop has in-built syntax
for initializing, incrementing, and testing the value of a counter, known as the
loop variable. Since here is a exact location in the loop syntax for an
increment operation, the increment and decrement operators are commonly
used as part of a for loop.
In the next example, we can see the value of I is outputted to the console and
increased by 1 during each iteration of the loop.
class ForLoopTest
{
static void Main()
{
for (int I = 1; I <= 10; I++) // creates an integer I = 1. Until I reaches 10

{ // increment counter

Console.WriteLine(I); // output I to the console

}
}
}

You will see: 1,2,3,4,5,6,7,8,9,10 on the console


Foreach loop
The foreach loop iterates through a collection of items, setting a loop variable
to represent each item in turn. Operations may be carried out on an item in the
body of the loop. One fine feature of foreach loop is that every item is iterated
over precisely once. So, it’s impossible to miscount and iterate past the end of
the collection, as can happen with other loops. The format of foreach is:
foreach(type variable in collection)
statement

The main points of the foreach statement:


type is used to declare the data type of the variable for every item in the
collection. This may be var, if so, the compiler deduces the type of the
item from the type of the collection.
variable is a read-only variable into which the foreach loop will
automatically allocate the subsequent item in the collection. Its scope is
restricted to the body of the loop.
collection is an expression, such as an array, representing any number of
items.
statement is the loop body that executes for each iteration of the loop
An example of the foreach loop:
class Program
{
static void Main()
{
string[] petAnimals = { "dog", "fish", "snake" };
// . . . Loop using foreach
foreach (string value in petAnimals)
{
Console.WriteLine(value);
}
}
}

You will see: dog, fish, snake, on the console.


Switch statement
A switch is easier to comprehend than a (complex) if statement when you have
a value that must be compared against numerous constant values. It has the
subsequent syntax:
Switch (expression)
{
case constant:
statements
default:
statements
}
Points to note about the expression are:
The value that is being compared to different constants goes where
‘expression’ is. The type of this expression governs the type of the
switch. Allowable governing data types are bool, sbyte, byte, short,
ushort, int, uint, long, ulong, char and enum type (discussed in types), the
corresponding nullable types of each of those value types, and string.
Any constant expression that works with the governing type considered a
constant.
The switch section is a collection of more than one case labels (or
default label) succeeded by a collection of one or more statement.
statements are one or more statements to be executed when the
expression equals one of the constant values stated in a label in the
switch section. The end point of the group of statements can’t be
reachable. Typically, the concluding statement is a jump (break, return
or goto) statement.
You can redraft the cascading if statement to the following switch statement:

switch (day)
{
case 0:
dayName = "Sunday";
break;
case 1:
dayName = "Monday";
break;
case 2:
dayName = "Tuesday";
break;
etc
default:
dayName = "Invalid";
break;
}
Switch statement rules
The switch statement is very valuable, but you can’t always utilise it. Any
switch statement you write must adhere to the following rules:
You can use switch only on certain data types, such as int, char, or string.
With any other types (including float and double), you must use an if
statement.
The case labels must be constant expressions, such as 42 if the switch
data type is an int, ‘4’ if the switch data type is a char, or “42” if the
switch data type is a string. If you must calculate your case label values
at run time, you need to use an if statement.
The case labels have to be unique expressions – i.e. two case labels
can’t have the same value.
it is possible to run the same statements for more than one value by
providing a list of case labels and no intervening statements. The code
for the last label on the list is executed for all cases in that list.
Although you will get a compiler error if a label has more than one
associated statements, execution can't fall through to the subsequent
statement.
The subsequent code fragment illustrates these points:
Switch (cards)
{
case Hearts:
case Diamonds: // Fall-through allowed – there is no code
between labels
colour = "Red"; // Code executed for Hearts & Diamonds
break;
case Clubs:
colour = "Black";
case Spades: // Code between labels -ERROR
colour = "Black";
break;
}
Break statement
To escape out of a loop or a switch statement, C# uses a break statement.
Every time the break statement is met, control instantly leaves the loop or
switch. For example, a conditional statement comprises of a counter that is
supposed to count from 1 to 100; however, the break statement terminates the
loop after 4 counts.
class BreakStatementTest
{
static void Main()
{
for (int k = 1; k<= 100;k++)
{
if (k == 5)
{ break; }
Console.WriteLine(k);
}
}
}
The output is: 1,2,3,4
Exceptions and Error handling
To date we have seen the main C# statements that you need to know to perform
common tasks like declaring variables, using operators to create values,
writing methods, writing if & switch statements to run code selectively; and
writing while, for, and do statements to run code repeatedly. However, these
statements don’t cover the chance or likelihood that things can go wrong.
C# has a feature called structured exception handling that lets you work with
situations where your methods aren’t able to fulfil their intended purpose. The
syntax for managing exception handling is the try (try is a C# keyword), catch
(catch is another C# keyword) and a finally (finally is also a C# keyword)
statement. All the code to be monitored for exceptions goes in the try block,
and the code that handles a potential exception goes in a catch block. The
finally statement ensures that code always runs, even after an exception has
occurred.
static void ManageANullReference()
{
Program prog = null;
try
{
Console.WriteLine(prog.ToString());
}
catch (NulReferenceException ex)
{
Console.Wrte(ex.Mesage); // Print the error message
}
}
In C#, any time you try to use a member of a null object, you’ll receive a
NullReferenceException error. The solution to fix the problem is to assign a
value to the variable.
Since the code that threw the exception is inside the try block, the code stops
execution of any of the code in the try block and starts looking for an exception
handler. The catch block parameter indicates that it can catch a
NullReferenceException if the code inside of the try block throws that
exception type. The body of the catch block is where you perform any
exception handling.
Catching multiple exceptions
The .NET Framework defines numerous types of exceptions. If you write a
program you probably don’t want to write catch handlers for every possible
exception that your code can throw. So, how do you ensure that your
programs catch and handle all possible exceptions?
The answer is the way the different exceptions are related to one another.
Exceptions are ordered into inheritance hierarchies. FormatException and
OverflowException both belong to a tree called SystemException.
SystemException belongs to a bigger tree simply called Exception, and base
call for all exceptions
The code following throws an exception in the try block with the different
exceptions caught.
The method is named HandleThisUncaughtException as there isn’t a specific
catch block to handle a NullReferenceException; the exception will be
handled by the catch block for the Exception type.
static void HandleThisUncaughtException()
{
Program prog = null;
try
{
Console.Write(prog.ToString());
}
catch (ArgumentNulException ex)
{
Console.Write("Argument Null Exception" + ex.Message);
}
catch (ArgumentExeption ex)
{
Console.Write("Argument Exception" + ex.Message);
}
catch (Exception ex)
{
Console.Wrte("Exception" + ex.Mesage);
}
finally
{
Console.Write("You will always get the finally statement.");
}
}

You list exceptions by their inheritance hierarchy, with top-level exceptions


lower in the list of catch blocks. A thrown exception will move down this list
of handlers, looking for a matching exception type, and only execute in the
catch block of the first handler that matches. ArgumentNullException
originates from ArgumentException, and ArgumentException originates from
Exception.
If no catch block can handle an exception, the code goes up the stack looking
for a potential catch block in calling code that can handle the exception type.
Your program will terminate should there be no code in the call stack.
Once the program initiates executing code in the try block, the finally block is
guaranteed to execute. If an exception happens and isn’t caught, the finally
block will execute before the program starts looking at the calling code for a
matching catch handler.
You can write a try-finally block (without catch blocks) to guarantee that
certain code will execute once the try block begins:
try
{
TrySomeCodeThatMightException();
}
finally
{
CleanupEvenOnFailure();
}
This is useful for opening a resource, like a file or database connection, and
then guaranteeing you will be able to close it regardless if an exception occurs
or not.

Throwing exceptions
Should you encounter a reason why your method can’t perform its intended
purpose, throw an exception.
The following exception types listed are used extensively throughout the CLR
& .NET Framework. You can throw them yourself or use them as a base for
deriving custom exception types.

System.ArguementException
Thrown when a function is called with a bogus argument. This generally
indicates a program bug.

System.ArguementNullException
Subclass of ArgumentException that’s thrown when a function argument is
(unexpectedly) null.

System.ArguementOutOfRangeException
Subclass of ArgumentException that’s thrown when a (usually numeric)
argument is too big or too small. E.g. this is thrown when passing a negative
number into a function which solely takes positive ones.

System.InvalidOperationException
Thrown when the state of an object is unsuitable for a method execute,
irrespective any particular argument values. E.g. when you read unopened file
or get the subsequent element from an enumerator where the underlying list has
been modified halfway through the iteration.

System.NotSupportedException
Thrown to indicate that a particular method or function isn’t supported.

System.NotImplementedExcepetion
Thrown to indicate that a function has not yet been employed

System.ObjectDisposedException
Thrown when the object upon which the function is called has been disposed.
There are many Exception-derived types in the .NET FCL which you can
utilize.
In this example, the .NET Framework’s ArgumentOutOfRangeException class
is one:
public static string monthName(int month)
{
switch (month)
{
case 1:
return "January";
case 2:
return "February";
case 3:
return "March";
case 4:
return "April";
case 5:
return "May";
case 6:
return "June";
case 7:
return "July";
case 8:
return "August";
case 9:
return "September";
case 10:
return "October";
case 11:
return "November";
case 12:
return "December";
default:
throw new ArgumentOutOfRangeException("No such month!");
}
}
Classes and objects
A class is a construct that enables you to create custom types by putting
together variables of other types, methods and events. An object is an instance
of that type, and is created once the program starts. Many objects can be
instances of the same class. A class is like a template. It states the data and
behaviour of a type. Should a class not be declared as static, the client code
can utilize it by generating objects or instances which are assigned to a
variable. That variable remains in memory until every reference to it go out of
scope. Once that occurs, the CLR denotes it as ready for garbage collection.
Should the class be declared as static, then only one copy will exist in memory
and client code can’t access it with an instance variable only through the class
itself.
Classes provide a convenient mechanism for modelling the entities
manipulated by applications. An entity can signify a specific item, like a client,
or something more abstract, like as an order. Part of the design process of any
system focuses on determining the entities that are important to the processes
that the system implements and then performing an analysis to see what
information these entities must hold and what operations they should perform.
You store the information that a class holds as fields and use methods to
implement the operations that a class can perform.
Encapsulation
This is the procedure of placing more than one, items together in a physical or
logical package and limiting access to it. The idea behind this OOP pillar is
that a program that uses a class shouldn’t have to worry how that class actually
works internally. The program simply creates an instance of it and uses it. As
long as those methods do what they say they will do, (and the program has
access to them) the program doesn’t care how they are implemented.
When you call the Console.WriteLine method, you don’t want to be concerned
with all the complex details of how the Console class gets data written on the
screen. A class might need to maintain all sorts of internal state information to
perform its various methods. This additional state information and activity is
hidden from the program that is using the class. So, encapsulation is sometimes
referred to as information hiding. Encapsulation actually has two purposes:
To combine methods and data within a class; in other words, to support
classification
To control the accessibility of the methods and data; in other words, to
control the use of the class
Declaring a class
Classes are declared by using the class keyword, as shown in the subsequent
example:
public class Consumer // Consumer class
{
// Fields, properties, methods and events for Consumer class go here…
}

The access level comes before the class keyword. Since public is used in this
case, there is complete access to create objects from this class. To declare a
class, you use the keyword class and then name of the class (class Consumer as
above). The remainder of the definition, i.e. the class body is in {brackets}
and holds the fields, properties, methods and events. They are jointly known as
class members.
Controlling accessibility
You can modify the definition of a field or method with the public and private
keywords to control whether it is accessible from the outside:
A method or field is private if it is accessible only from inside the
class. To declare that a method or field is private, you write the keyword
private before its declaration. As intimated previously, this is actually
the default, but it is good practice to state explicitly that fields and
methods are private to avoid any confusion.
A method or field is public if it is available from both inside & outside
of the class. To declare that a method or field is public, you write the
keyword public before its declaration.
Creating an object
Even though they are frequently utilized interchangeably, a class and object are
not the same. A class specifies plan for an object but is not the actual object
itself. An object is occasionally identified as an instance of a class and is a
concrete entity based on a class.
Objects can be created by using the new keyword followed by the name of the
class that the object will be based on; the following create a new object from
Consumer class created in the previous example:
Consumer object1 = new Consumer();
When an instance of a class is created, a reference to the object is returned to
the developer. In the previous code list, object1 is a reference to an object that
is based on Consumer. This reference refers to the new object but doesn’t
contain the object data itself.

Constructors
Every class that is created needs a constructor. A constructor has the identical
name as the class, it can take parameters, but is unable to return a value (not
even void). It’s mandatory to have a constructor and if you don’t write one, the
compiler generates a default constructor on your behalf. To write your own
constructor just add a public method that doent return a value and give it the
same name as the class. E.g. the following shows the Circle class with a
default constructor that initializes the getCircleRadius field to 0:
class Circle
{
private int getCircleRadius;
public Circle() // The default constructor
{
getCircleRadius = 0;
}
public double GetArea()
{
return Math.PI * getCircleRadius * getCircleRadius;
}
}
In this example, the constructor is marked as public. If this keyword is left out,
the constructor will be private (like any other methods and fields). If the
constructor is private, it cannot be used outside the class, which prevents you
from being able to create Circle objects from methods that are not part of the
Circle class. Private constructors do have limited uses.
Having added a public constructor, you can now use the Circle class and
exercise its Area method. Notice that you use a dot notation to invoke the area
method on a Circle object:
Circle c; // Creates a Circle object
c = new Circle(); // Initialize it
double areaOfCircle = c.GetArea();

Static Classes
A static class is basically the same as a non-static class, but there is one
difference: a static class cannot be instantiated – i.e. you can’t generate a
variable of the class type via the new keyword. To access the members of a
staic class you utilise the class name itself. The subsequent static class called
UtilityClass has a public method called MethodA, You can invoke this method
like so:
UtilityClass.MethodA();
The goal of a static class is solely to act as a holder of utility methods and
fields. A static class cannot contain any instance data or methods, and it does
not make sense to try to create an object from a static class by using the new
operator.
Value types and Reference types
Types in C# can be split into either value types or reference types. The
differences between the types in each category stem from differences in
copying strategies, which in turn result in each type being stored differently in
memory.
Value types
Value types encompass most built-in types (In specific terms, all numeric
types, char type, and bool type) as well as custom struct and enum type. These
types all have a fixed size, variables of value types directly contain their own
values.
Reference types
Reference types comprise all classes, array, delegate and interface types and
are handled differently by the compiler. For example, take the Circle Class
type (previous code listing). Once you declare a Circle variable, the compiler
allocates a small portion of memory which can possibly hold the address of
(or a reference to) additional block of memory holding a Circle. Only once an
actual Circle object is created (via the new keyword) then the memory is
allocated.
Copying value & reference types
When you take a copy of a value type there are two memory locations. For
example, should you create a integer variable called i and give it the value 42
then an additional integer variable named copyi and assign i to copyi, copyi
will hold the identical value as i (42). Although copyi and i hold the exact
same value, there are actually two blocks of memory holding the value 42: one
block for i and another block for copyi. If you adjust the value of i, the value of
copyi doesn’t change:
int i = 42; // declare i as integer & assign it 42
int copyi = i; /* decclare copyi equal to i (i.e copyi now holds a
copyi of i – its value 42) */
i++; /* incrementing i by 1. copyi is unchanged;
I now holds 43, but copyi still has 42 value*/
This is in marked difference to declaring a variable as a class type where you
are essentially copying the same address. E.g. if you declare c as a Circle, c
can refer to a Circle object; the actual value held by c is the address of a
Circle object in memory. Should you declare a further variable called refc (a
Circle) and assign c to refc, refc will have a copy of the identical address as
c. To summarize, both refc and c now denote the one Circle object.
Circle c = new Circle(42); // declare new c variable of Cirlce object that = 42
Circle refc = c; // assign c to refc. refc has identical address as c

Note that the behaviour of method parameters hinge on on whether they are
value types or reference types.
Null values
The null value identified with the null keyword, indicates that the variable
does not refer to any valid object, i.e. it stipulates that a variable is set to
nothing. You can assign reference types, pointer types and nullable types the
value null. Code that sets a variable to null explicitly assigns the reference to
refer to no valid value. It is possible to check whether a reference refers to
nothing. The subsequent code demonstrates assigning null to a string variable:
static void Main()
{
String phoneNum;
// …
// Clear the value of phoneNum.
phoneNum = null;
//..
}
Assigning the value null to a reference type is not the same as not assigning it
at all. In other words, a variable that has been assigned null has still been set,
whereas a variable with no assignment has not been set and therefore, will
often result in your program not compiling if used prior to assignment.
Assigning a string value the value null is particularly dissimilar from assigning
an empty string, “”. Use of null indicates that the variable has no value,
whereas “” indicates that there is an empty value – an empty string. This
difference is quite valuable in programming, you could take a phone number of
null to mean that the phone number is unknown, while a phoneNum value of “”
could stipulate no phone exists.
Nullable types
Value types can’t typically be assigned null since by definition they can’t hold
references, which includes references to nothing. However, C# defines a
modifier that you can use to declare that a variable is a nullable value type. A
nullable value type acts in a similar way to the original value type, but you can
assign the null value to it. You use the (?) to specify that a value type is
nullable, like so:
int? i = null; // valid code
You can ascertain whether a nullable variable contains null by testing it in the
same way as a reference type:
if (i == null)
The System.Object class
One of the most important reference types in the .NET Framework is the
Object class in the System namespace. To completely appreciate the
significance of the System.Object class you need under​stand inheritance -
described later in this Ebook. For the time being, simply accept that all
classes are specialized types of System.Object and that you can use
System.Ob​ject to create a variable that can refer to any reference type.
System.Object is such an important class that C# provides the object keyword
as an alias for System.Object.
In the subsequent example, the variables c and o both reference the same
Circle object. The fact that the type of c is Circle and the type of o is object
(the alias for System.Object) in effect offers two dif​ferent views of the same
item in memory.
Circle c;
c = new Circle(42);
object o;
o = c;
Boxing
As discussed, variables of type object can refer to any item of any reference
type. However, variables of type object can also refer to a value type. To
illustrate, both the two following statements initialize the variable i (of type
int, a value type) to 42 and then initialize the variable o (of type object, a
reference type) to i:
int i = 42;
object o = i;
In the second there is a bit more happening. Re​member that i is a value type
and that it lives on the stack. Should the reference inside o referred directly to
i, then the reference would refer to the stack. Nevertheless, all references must
refer to objects on the heap; creating references to items on the stack could
seriously compromise the robustness of the runtime and create a potential
security flaw, so it is not allowed. Therefore, the runtime allocates a piece of
memory from the heap, copies the value of integer i to this piece of memory,
and then refers the ob​ject o to this copy. Boxing is term for automatically
copying an item from the stack to the heap.
Unboxing
Because a variable of type object can refer to a boxed copy of a value, it’s
only reasonable to allow you to get at that boxed value through the variable.
You may be thinking that could can access the boxed int value that a variable o
refers to via a simple assignment statement like:
int i = o;
This however will result in a compile error. You can’t use the int i = o code.
The variable o could be referencing absolutely almost anything - not just an
integer. Take for example the subsequent code if such a statement were
allowable:
Circle c = new Circle();
int i = 42;
object o;
o = c; // o refers to a circle
i = o; // what is stored in i?
To get the value of the boxed copy, you must utilise what is known as a cast.
This operation checks if it’s safe to convert an item of one type to another
before it actually making the copy. You prefix the object variable with the
name of the type in parentheses, as follows:
int i = 42;
object o = i; // boxing ok
i = (int)o; // this compiles ok
The effect of this cast is subtle. The compiler sees that you’ve specified the
type int in the cast. It generates code to check what o actually refers to at run
time. It could be really anything. Even though your cast says o refers to an int,
it doesn’t mean that it actually does. If o does actually refer to a boxed int and
everything correlates, the cast will succeed and the compiler will extract the
value from the boxed int and copy it to i. (i.e. the boxed value will be stored in
i.) This is called unboxing

However, if o does not refer to a boxed int, there has been a type mismatch and
the cast will fail. InvalidCastException is invoked. The following illustrates
an unboxing cast that fails:
Circle c = new Circle(42);
object o = c; // fails to box since Circle is a reference variable
int i = (int)o; // compiles ok but throws an exception @ run time
Note that boxing and unboxing are expensive operations because of the quantity
of checking that is required and the need to allocate additional heap memory.
Boxing is useful but overuse will really negatively impact the performance of
your pro​gram.

Casting data safely


By utilising a cast, you can in your opinion specify that the data referenced by
an object has a specific type and it is safe to reference the object by using that
type. It is important to note that it is of your opinion. The C# compiler will not
check that this is the case, but the runtime will. If the type of object in memory
doesnt match the cast, the runtime will throw an InvalidCastException. You
should expect this exception and and deal with it appropriately should it occur.
In saying that, catching an exception and attempting to recover in the event that
the type of an object is rather an unwieldly approach. C# offers two really
useful operators that can help you perform casting in a much more elegant
manner: is and as operators.

The is operator
You can utilise the is operator to authenticate that the type of an object is what
you assume it to be, like so:
WrappedInteger wi = new WrappedInteger();
...
object o = wi;
if (o is WrappedInteger)
{
WrappedInteger temp = (WrappedInteger)o;
// This is safe;
o is a WrappedInteger
...
}
The is operator accepts two operands: the left - a reference to an object, the
right – a type. Should the type of the object, referred to on the heap, has the
specified type, it evaluates to true; or else, it evaluates to false. The prior code
tries to cast the reference to the object variable o only if it knows that the cast
will be successful.

The as operator
The as operator achieves a similar role to is but in a slightly condensed
method. You utilise the as operator like so:
WrappedInteger wi = new WrappedInteger();
...
object o = wi;
WrappedInteger temp = o as WrappedInteger;
if (temp != null)
{...
// Cast was a success !
}
The as operator is similar to the is operator in that it takes an object and a type
as its operands. The runtime at​tempts to cast the object to the specified type. If
the cast is a success, the result is returned and is assigned to the
WrappedInteger variable. Should the cast fail, then the as operator appraises
to the null value and instead assigns that to temp.
Enumerations
An enum is a value type that the developer can declare. The key characteristic
of an enum is that it declares at compile time a set of possible constant values
that can be referred to by name. The subsequent is an example of an enum:
enum Season { Spring, Summer, Autumn, Winter }

Once you have declared an enum, you can use it in the exact same way as any
other type. That is, if the name of your enum is Season then you can create
variables, fields and parameters of type Season as demonstrated here:
enum Season { Spring, Summer, Autumn, Winter }
class Example
{
public void Method(Season parameter) // method parameter
{
Season localVariable; // local variable
...
}
private Season currentSeason; // private field
}
In order to read an enumeration, you must assign a value to it. You can assign a
value that is defined by the enumeration only to an enumeration variable, as is
illustrated here:
Season colourful = Season. Autumn;
Console.WriteLine(colourful); // writes out ‘Autumn'
As you can with all value types, you can create a nullable version of an
enumeration variable by using the ? modifier. You can then assign the null
value, as well the values defined by the enumeration, to the variable:
Season? colourful = null;
Structures
Classes specify reference types that are solely created on the heap. However,
on some occasions the class may have so little data that the overhead of
managing the heap turns out to be disproportionate. In such cases, it is best to
define the type as a structure which is a value type. Since structs are stored on
the stack, as long as the structure is reasonably small, the memory management
overhead is often reduced.
A structure is similar to a class in that it can have its own fields, methods, and
constructors.
Declaring a structure is similar to that of a class. You utilize the keyword
struct then use the name of the type, then followed by the body of the structure,
between opening and closing braces.
Here for example is a structure named Time that contains three public int fields
named hours, minutes, and seconds:
struct Time
{
public int hours, minutes, seconds;
}
As per classes, it is not recommended to make the fields of a structure public
in most cases; as there is no way to control the values held in public fields.
Anyone could for example, set the value of minutes or seconds to a value
greater than 60. A better idea is to make the fields private and provide your
structure with constructors and methods to initialize and manipulate these
fields, as shown in this example:
struct Time
{
private int hours, minutes, seconds;
...
public Time(int hh, int mm, int ss)
{
this.hours = hh % 24;
this.minutes = mm % 60;
this.seconds = ss % 60;
}
public int Hours()
{
return this.hours;
}

When you copy a value type variable, you get two copies of the value. With
reference types however, once you copy a variable of reference type, you get
two references to the said object. In summary, use structures for small data
values for which it’s just as or nearly as efficient to copy the value as it would
be to copy an address. Utilise classes for larger more complex data where
copying is too inefficient.
Differences between structures and classes
Syntactically a structure and a class are somewhat alike, although there are a
few significant differences. Firstly, its impossible to declare a default
constructor (i.e. a constructor with zero parameters) for a structure. In the next
example the code would compile if Time were a class, but since Time is a
structure, it doesn’t:
struct Time
{
public Time() { . . . } / Results in compile time error

}

Secondly in a class, you can initialize instance fields at their point of


declaration. In a structure, you cannot. In this next example, the code would
compile if Time were a class, but because Time is a structure, it triggers a
compile-time error:
struct Time
{
private int hours = 0; // Results in compile time error
private int minutes;
private int seconds;
...
}

The main differences between a structure and a class as summarized here:


Question Structure Class
What type is it? Value type. Reference type.

Are instances on the Structure instances Class instances known as


stack or the heap? known as values & live objects & live on the heap.
on the stack.

Can you declare No. Yes.


a default construc​tor?

If you declare your own


constructor, will the compiler
still generate the default
constructor? Yes. No.

Will the compiler


automatically initialize a
field for you in the
constructor if you don’t? No. Yes.

Can you initialize instance


fields at their point of
declaration? No. Yes.
Arrays
You can define an array as an unordered sequence of items. As opposed to
fields in a structure or class which may have different types, all the items in an
array have the identical type. In addition, items in an array live in a contiguous
block of memory and are accessed by using an index as opposed tofields in a
structure or class, which are accessed by name.
Declaring array variables
In order to declare an array variable, you stipulate the name of the element
type, then use a pair of square brackets and finally by the variable name. The []
square brackets denote that the variable to be an array. So, to declare an array
of integer variables named pins (in order to hold a set of personal id numbers)
you write the following:
int[] pins; // Personal Id Numbers
You are not just limited to primitive types as array elements, you may also
create arrays of structures, enumerations, and classes. For example, you can
construct an array of Date structures like so:
Date[] dates;
Creating an array instance
In order to create an array instance, you use the new keyword, element type
and size of the array you’re forming enclosed in [] square brackets. Generating
an array will also initializes its elements with the default values: 0 (numeric)
null (reference) or false (Boolean). To create and initialize a new array with
four integers for the pins variable declared previous, you write the following:
pins = new int [4];
Since the memory for the array instance is allocated dynamically, array size
doesn’t need to be a constant; it can be worked out at run time. You write the
following:
int size = int.Parse(Console.ReadLine()); // Get the size of array from console
int [] pins = new int [size]; // Create new array of pins based on user
input
Likewise, you can create an array size of 0. This might sound strange however
it’s quite valuable when the array size is resolved dynamically and might even
be 0. The 0 size is an array containing zero elements and is not a null array.
Populating and using an array
Whenever you create an array instance, every element of the array is initialized
to a default value depending on their type. Numeric values for example, all
default to 0, objects are initialized to null and strings are set to null. You can
adjust this behaviour and initialize the elements of an array to precise values if
you wish. You achieve this by producing a comma-separated list of values
between a pair of braces. So, in order to initialize an array of 4 pins (of
integer value) whose values are 9, 3, 7, and 2, you code the following:
int[] pins = new int[4] { 8, 5, 6, 1 };
The values in between the braces don’t have to be constants; they can be
values worked out at run time, as shown in the following lines of code:
Random randomExampleArray = new Random();
int[] pins = new int[4]{ randomExampleArray.Next() %
10,randomExampleArray.Next() % 10,
randomExampleArray.Next() % 10, randomExampleArray.Next() % 10 };
// populates array with 4 random numers
The number of values between the braces must match precisely the size of the
array instance being created:
int[] pins = new int[3] { 8, 5, 6, 1 }; // Results in a compile time error +1
int[] pins = new int[4] { 8, 5, 6 }; // Results in a compile time error -1
int[] pins = new int[4] { 8, 5, 6, 1 }; // This is correct
Creating an implicitly typed array
Once you declare an array the element type must match the type of elements in
the array. For example, if you declare pins to be an array of int, (as above),
you cannot store a double, string, struct, or anything that is not an int in this
array. If you stipulate a list of initializers when declaring an array, you can let
the C# compiler infer the actual type of the elements in the array for you, like
this:
var names = new[] { "Luis", "Rossanna", "Joelle", "Jannett" };

In the above example, the C# compiler determines that the names variable is an
array of strings. Note, 1) you leave out the [] square brackets from the type; the
names variable are declared simply as var, not var[]. 2) you must stipulate the
new operator and square brackets before the initializer list.
If you utilize this syntax, you must ensure that each of the initializers have the
same type. This following causes the compile-time error:
var bad = new[] { "Luis", "Rossanna", 97, 101 }; // Error No best type found for
implicitly
typed array
Accessing an individual array element
To access an individual array element, you must provide an index signifying
which element you need. Array indexes are zero-based; so, the initial element
of an array lives at index 0 not index 1. An index value of 1 gets the second
element. You can read for example, the contents of element 2 of the pins array
into an int variable by using the following code:
int myPin;
myPin = pins[2];
Likewise, you can change the contents of an array by assigning a value to an
indexed element:
myPin = 9627;
pins[2] = myPin;
All array element access is bounds checked and should you stipulate an index
that is less than 0 or greater than or equal to the length of the array, the
compiler will throw an IndexOutOfRangeException exception, as in this
example:
try
{
int[] pins = { 8, 5, 6, 1 }; // Array of 4 items
Console.WriteLine(pins[4]); // No 5th item in array
}
catch (IndexOutOfRangeException ex)
{
Console.WriteLine("There has been an error: "+ex); // Output error to
console
}
Iterating through an array
All arrays are really instances of the System.Array class in the .NET
Framework, and this class specifies numerous valuable properties and
methods. You can for example, query the Length property to learn how many
elements there are in an array and iterate through all the elements of an array
via a for statement. The subsequent code outputs the array element values of
the pins array to the console:
int[] pins = { 8, 5, 6, 1 }; // Create an array of 4 pins
for (int arrayIndex = 0; arrayIndex < pins.Length; arrayIndex++)// loop
through array
{
int pin = pins[arrayIndex];
Console.WriteLine(pin); // This will output all items in pin to console
}

Often new developers fail to recall that arrays start at element 0 and that the
last element is numbered Length – 1. C# provides the foreach statement with
which you can iterate through the elements of an array without worrying about
these issues. Here for example, is he preceding for statement rewritten as a
comparable foreach statement:
int[] pins = { 8, 5, 6, 1 };
foreach (int pin in pins)
{
Console.WriteLine(pin);
}
An iteration variable (i.e. pin) is declared in the foreach statement and it
obtains each value of every item in the array. The type of this variable has to
match the type of the elements in the array. The foreach statement is the
favoured way to iterate through an array; it expresses the purpose of the code
directly, and all the the for loop is dropped. However, sometimes, you will
have to revert to a for statement because:
A foreach statement always iterates through the entire array. If you wish
to iterate through a partial part of an array (e.g. the first half) or bypass
some elements (like every second element), it’s much easier to utilise a
for statement.
A foreach statement always iterates from arrayIndex 0 through
arrayIndex Length – 1. Should you wish to iterate backward or in
another sequence, it’s easier to use a for statement.
If the body of the loop needs to know the arrayIndex of the element
rather than just the value of the element, you’ll have to use a for
statement.
If you need to adjust the elements of the array, you will have to utilise a
for statement as the iteration variable of the foreach statement is a read
only copy of each element of the array.
Using multidimensional arrays
The arrays to date have contained a single dimension, and you can think of
them as simple lists of values. You can produce arrays with more than one
dimension. To create a two-dimensional array, you specify an array that needs
two integer indexes. The subsequent code produces a two-dim array with 20
ints named items. You can think of an array like a table where the first
dimension stipulates a number of rows, and the second stipulates a number of
columns.
int[,] items = new int[4, 5];
To get to an element in the array, you must provide two index values to specify
the “cell” holding the element. The subsequent code shows some examples
using the items array:
items[2, 3] = 88; // set the element at cell(2,3) to 88
items[2, 4] = items[2, 3]; // copy the element in cell(2, 3) to cell(2, 4)
items[2, 4]++; // increment the integer value at cell(2, 4)

You can create endless dimensions on an array. The following example


generates and utilises an array called cube that contains three dimensions. If
you wish to retrieve an element in the array you must stipulate three indexes.
int[,,] cube = new int[5, 5, 5];
cube[1, 2, 1] = 101;
cube[1, 2, 2] = cube[1, 2, 1] * 3;
Since arrays take a lot of memory, an array with more three dimensions could
potentially cause problems. Just to note, a cube array contains 125 elements (5
* 5 * 5). A four-dimensional array, each dimension having a size of 5
comprises of 625 elements. It’s quite easy to run out of memory so, you should
always be prepared to catch and handle OutOfMemoryException exceptions.
Parameter arrays
As discussed earlier in this Ebook overloading is the technical term for
declaring two or more methods with the same name in the same scope.
However, overloading doesn’t easily handle a situation in which the type of
parameters doesn’t vary but the number of parameters does.
By utilising the params keyword, you can stipulate a method parameter that
takes a variable number of arguments. For example, you can send a comma
separated list of arguments of type (definied in the parameter declaration), an
array of arguments of the specified type, no arguments (thus length of the
params list is zero).
No extra parameters are allowed after the params keyword and only one
parameter is allowed in a method declaration. An example of a parameter
array:
using System;
namespace ArrayApplication
{
class ParamArray
{
public int AddElements(params int[] arr)
{
int sumTotal = 0;
foreach (int i in arr)
{
sumTotal += i;
}
return sumTotal;
}
}
class TestClass
{
static void Main(string[] args)
{
ParamArray app = new ParamArray();
int sumTotal = app.AddElements(412,620, 350, 467, 689);
Console.WriteLine("The total sum equal: {0}", sumTotal);
Console.ReadKey();
}
}
}

The following is outputted to the console: The total sum equals: 2538
Inheritance
Inheritance permits you to generate new classes which reuse, extend, and
modify the behaviour from other classes. Together with encapsulation and
polymorphism they form the pillars or characteristics of object-oriented
programming (O.O.P).
You utilise inheritance you declare that a class inherits from another class like
so:
class DerivedClass : BaseClass
{
...
}

The base classes methods become part of the derived classes. In C#, a class is
allowed to derive from one base class maximum; a class isn’t allowed to
derive from two or more classes. Except however, a DerivedClass is stated as
sealed, you can create additional derived classes that inherit from
DerivedClass using the same syntax
Base class constructors
Along with the methods which it inherits, a derived class automatically
contains all the fields from the base class. These fields usually require
initialization when an object is created. You typically perform this sort of
initialization in a constructor. You can specify the base keyword to call a
base-class constructor when you define a constructor for an inheriting class, as
illustrated in this example:
class Reptile // Reptile - base class
{
public Reptile(string reptileName) // constructor for base class
{
...
}
...
}
class Alligator : Reptile // Alligator - the derived class
{
public Alligator(string reptileName)
: base(reptileName) // calls Reptile(reptileName)
{
...
}
...
}

}
Virtual methods
When a method in a base class is declared virtual, a derived class can
override the method with its own implementation. Occasionally virtual is used
to hide a method.
A method that is envisioned to be overridden is called a virtual method.
Overriding a method is a mechanism for offering different implementations of
the same method—the methods are all related because they are intended to
perform the same task, but in a class-specific manner. Hiding a method is a
way of substituting one method with another—the methods are typically
unrelated and may perform completely different tasks. Overriding a method is
a useful programming concept; hiding a method is often an error.
You mark a method as a virtual method by using the virtual keyword. For
example, the ToString method in the System.Object class is defined like this:
namespace System
{
class Object
{
public virtual string ToString()
{
...
}
...
}
}
Override methods
If a base class states that a method is virtual, a derived class can use the
override keyword to declare another implementation of that method, as shown
here:
class Alligator : Reptile
{
...
public override string ToString()
{
...
}
}
It is possible for the implementation of the method in the derived class to call
the original implementation of the method in the base class. This is achieved
by utilising the base keyword, like so:
public override string ToString()
{
base.ToString();
...
}

When you declare polymorphic methods by using the virtual and override
keywords you must ensure the following:
A virtual method can’t be private, since it is intended to be made
accessible to other classes via inheritance. Likewise, override methods
can’t be private since a class can’t change the protection level of a
method that it inherits. However, override methods can have a special
form of privacy known as protected access, as you will find out in the
next section.
The signatures of the virtual and override methods must be identical;
they must have identical name, number, and types of parameters. In
addition, both methods must return the same type.
You can only override a virtual method. Should the base class method
not be virtual and you attempt to override It, it will ensue in a compile
error. This is logical; it should be up to the developer of the base class
to decide whether its methods can be overridden.
If the derived class does not declare the method by using the override
keyword, it does not override the base class method; it hides the method.
I.e. it becomes an implementation of a completely different method that
happens to have the identical name. Like before, you will get a compile
time hiding warning, which you can silence by utilising the new
keyword.
An override method is implicitly virtual and it’s possible for it to be
overridden in a subsequent derived class. You can’t however explicitly
declare an override method as virtual by utilising the virtual keyword.
Protected access
The public and private access keywords either ensure access for everyone or
only to the class itself. In most cases these two options are enough.
However, as all experienced object-oriented programmers know, isolated
classes cannot solve complex problems. Inheritance is a very effective way of
connecting classes, and evidently there is a special and close relationship
between a derived class and its base class. Frequently, it is useful for a base
class to allow derived classes to access some of its members while hiding
these same members from classes that are not part of the inheritance. It is
possible with the protected keyword. It works like this:
If a class A is derived from another class B, it can access the protected
class members of class B. Put another way, inside the derived class A, a
protected member of class B is effectively public.
If a class A is not derived from another class B, it cannot access any
protected members of class B. So, inside class A, a protected member of
class B is regarded as private.
Extension methods
Extension methods facilitate you to augment methods to existing types without
having to create a new derived type, recompiling, or otherwise modify the
original
type. You can consider them as special type of static method, although they are
called as though they were instance methods on the extended type.
using System;
public static class ExtensionMethodsExample
{
public static string UppercaseTheFirstLetter(this string inputString)
{
// The following will uppercase the first letter in inputString
if (inputString.Length > 0)
{
char[] array = value.ToCharArray();
array[0] = char.ToUpper(array[0]);
return new string(array);
}
return inputString;
}
}
class Program
{
static void Main()
{
// Utilise the string extension method on this value.
string inputString = "The c# programming language";
inputString = inputString.UppercaseFirstLetter();
Console.WriteLine(inputString);
}
}

The output on the console is: The c# programming language


Interfaces
Inheriting from a class is a powerful mechanism, but the real power of
inheritance comes from inheriting from an interface. An interface does not
contain any code or data; it just specifies the methods and properties that a
class that inherits from the interface must provide. Utilising an interface makes
it possible to completely separate the names and signatures of the methods of a
class from the method’s implementation.
In numerous ways, abstract classes are very similar to interfaces excepting the
fact that they can contain code and data. However, you can specify that certain
methods of an abstract class are virtual so that a class that inherits from the
abstract class must provide its own implementation of the methods. Frequently
you use abstract classes with interfaces, and together they provide a key
technique with which you can build extensible programming frameworks
Defining an interface
Defining an interface is syntactically similar to defining a class, except that you
use the interface keyword instead of the class keyword.
interface IWaterBased
{
int NumberOfLegs();
}
Implementing an interface
To implement an interface, you declare a class or structure that inherits from
the interface and that implements all the methods specified by the interface
class Alligator : IWaterBased
{
...
public int NumberOfLegs()
{
return 4;
}
}
When you implement an interface, you must ensure that each method matches
its corresponding interface method exactly, according to the following rules:
The method names and return types match exactly.
Any parameters (including ref and out keyword modifiers) match
exactly.
Every method which implements an interface has to be publicly
accessible. Although if you are using an explicit interface
implementation, the method shouldn’t have an access qualifier.
If there is any difference between the interface definition and its declared
implementation, the class will not compile.
It is possible for a class to inherit from another class and implement an
interface simultaneously. To do this C# uses a positional notation: i.e. initially
its the base class followed by a comma and fially the interface. The following
example defines Alligator as a class that is a Reptile but that additionally
implements the IWaterBased interface:
class Reptile
{
...
}
class Alligator : Reptile, IWaterBased
{
public int NumberOfLegs()
{
return 4;
}
}
Referencing a class through its interface
In the same way that you can reference an object by using a variable defined as
a class that is higher up the hierarchy, you can reference an object by using a
variable defined as an interface that its class implements. In the previous
example, you can reference an Alligator object by using an IWaterBased
variable, as follows:
Alligator myAlligator = new Alligator();
IWaterBased iMyAlligator = myAlligator; // This is legal
This is valid because all Alligators are water-bound Reptiles, although the
converse is not true—you cannot assign an IWaterBased object to an Alligator
variable without casting it first to verify that it does actually reference an
Alligator object and not some other class that also happens to implement the
IWaterBased interface.
The technique of referencing an object through an interface is useful because
you can use it to define methods that can take different types as parameters, as
long as the types implement a specified interface. For example, the
FindWaterSpeed method shown here can take any argument that implements the
IWaterBased interface:
int FindWaterSpeed(IWaterBased WaterBasedReptile)
{
...
}

You can verify that an object is an instance of a class which implements a


specific interface by using the is operator. You use the is operator to determine
whether an object has a specified type, and it works with interfaces as well as
classes and structs. For example, the
following block of code checks that the variable myAlligator actually
implements the IWaterBased interface before attempting to assign it to an
IWaterBased variable:
if (myAlligator is IWaterBased)
{
IWaterBased iWaterBasedAnimal = myAlligator;
}
Note that when referencing an object through an interface, you can invoke only
methods that are made available through the interface.
Multiple interfaces
A class can have at most one base class, but it is allowed to implement
unlimited interfaces. Should a class implement an interface, then it must
implement each interface method, you specify each of the interfaces via a
comma separated list, like so:
class Alligator : Reptile, IWaterBased, IHuntable
{
...
}
Explicitly implementing an interface
The examples so far have shown classes that implicitly implement an interface.
Revisiting the IWaterBased interface and the Alligator class (shown next),
although the Alligator class implements from the IWaterBased interface, there
is nothing in the implementation of the NumberOfLegs method in the Alligator
class that says it is part of the IWaterBased interface:

interface IWaterBased
{
int NumberOfLegs();
}
class Alligator : IWaterBased
{
public int NumberOfLegs()
{
return 4;
}
}

This might not be an issue in a simple situation, but suppose the Alligator class
implemented multiple interfaces. There is nothing to stop multiple interfaces
from specifying a method with the identical name, although they might have
different meanings. Say for example you wanted to implement a swamp tour
based on alligators. A long swamp tour might be broken down into several
parts or legs. If you wanted to keep track of how many legs of the tour each
alligator was available to see you might do the following:
interface ISwampTour
{
int NumberOfLegs();
}
class Alligator : IWaterBased, ISwampTour
{
public int NumberOfLegs()
{
return 4;
}
}

Now, if you implement this interface in the Alligator class, you have an
interesting problem:
This is legal code, but does the Alligator have four legs, or is it available in
four legs of the swamp tour. The answer as far as C# is concerned is both of
these! By default, C# does not distinguish which interface the method is
implementing, so the same method actually implements both interfaces.
To solve this problem and disambiguate which method is part of which
interface implementation, you can implement interfaces explicitly. To do this,
you specify which interface a method belongs to when you implement it, like
this:
class Alligator : IWaterBased, ISwampTour
{
int IWaterBased.NumberOfLegs()
{
return 4;
}
int ISwampTour.NumberOfLegs()
{
return 3;
}
}

Now, you can see that the Alligator has four legs and has been on three legs of
the swamp tour.
Apart from prefixing the name of the method with the interface name, there is
one other subtle difference in this syntax: The methods are not marked as
public. You cannot specify the protection for methods that are part of an
explicit interface implementation. This leads to another interesting
phenomenon. If you create an Alligator variable in code, you cannot actually
invoke either of the NumberOfLegs methods, because they are not visible. As
far as the Alligator class is concerned, they are both private. In fact, this makes
sense. If the methods were visible through the Alligator class, which method
would the following code actually invoke, the one for the IWaterBased
interface or the one for the ISwampTour interface?
Alligator Alligator = new Alligator();
...
int legs = Alligator.NumberOfLegs();
How do you access these methods? The answer is that you reference the
Alligator object through the appropriate interface, like this:
Alligator Alligator = new Alligator();
...
ISwampTour swamptourAlligator = Alligator;
int legsInSwamptour = swamptourAlligator.NumberOfLegs();
IWaterBased WaterBasedAlligator = Alligator;
int legsOnAlligator = WaterBasedAlligator.NumberOfLegs();
It is recommended to explicitly implementing interfaces when possible.
Interface restrictions
It’s important to remember that interface never contains any implementation.
To ensure that this rule is never broken you must adhere to the subsequent
points:
You’re can’t define any fields in an interface, not even static fields.
Since a field is an enactment detail of a class or structure.
You can’t define any constructors in an interface. A constructor is also
considered to be an enactment detail of a class or structure.
You’re not allowed to define a destructor in an interface. (Destructors
are described in Garbage collection.)
You can’t stipulate an access modifier for any method. Every method in
an interface is implicitly public.
You can’t nest any types in an interface.
You can’t inherit from a struct or a class with an interface, although an
interface can inherit from another interface. Since structures and classes
contain implementation, an interface can’t inherit from either (i.e.
inheriting implementation).
Abstract classes
You can implement the IWaterBased and IHuntable interfaces discussed
before in many different classes, depending on how many different types of
Reptiles you want to model in your C# application. In situations, such as this,
it’s quite common for parts of the derived classes to share common
implementations. For example, the duplication in the following two classes is
obvious:

class Alligator : Reptile, IWaterBased, IHuntable


{
void IHuntable.EatCrayFish()
{
Console.WriteLine("Chewing cray fish");
// code for chewing cray fish
}
...
}
class Crocodile : Reptile, IWaterBased, IHuntable
{
void IHuntable.EatCrayFish()
{
Console.WriteLine("Chewing cray fish");
// same code as Alligator for chewing cray fish
}
...
}
Duplication in code is a warning sign. If possible, you should refactor the code
to evade this duplication and reduce any associated maintenance costs. One
way to achieve this refactoring is to put the common implementation into a new
class created specifically for this purpose. In effect, you can insert a new class
into the class hierarchy, as shown by the ensuing code example:
class MeatEatingReptile : Reptile, IHuntable
{
void IHuntable.EatCrayFish()
{
// common code for chewing cray fish
Console.WriteLine("Chewing cray fish");
}
}
class Alligator : MeatEatingReptile, IWaterBased
{

}
class Crocodile : MeatEatingReptile, IWaterBased
{

}

This is a good solution, but there is one thing that is still not quite right: you
can actually create instances of the MeatEatingReptile class (and the Reptile
class, for that matter). This doesn’t really make sense. The MeatEatingReptile
class exists to provide a common default implementation. Its sole purpose is to
be a class from which to inherit. The MeatEatingReptile class is an
abstraction of common functionality rather than an entity in its own right.
To declare that creating instances of a class is not allowed, you can declare
that the class is abstract by using the abstract keyword, such as in the next
example:
abstract class MeatEatingReptile : Reptile, IHuntable
{
...
}

Trying to instantiate a MeatEatingReptile object, will result in a compile


error:
MeatEatingReptile myMeatEatingReptile = new MeatEatingReptile(); //
compile error
Abstract methods
Inside an abstract class, you can have abstract methods which are comparable
in principle to a virtual method however it doesn’t contain a method body. If
its a derived class then it must override this method. The following example
defines the DigestCrayfFish method in the MeatEatingReptile class as an
abstract method; MeatEating Reptiles might use the same code for chewing
cray fish, but they must provide their own implementation of the
DigestCrayfFish method. An abstract method is useful if it does not make
sense to provide a default implementation in the abstract class but you want to
ensure that an inheriting class provides its own implementation of that method.
abstract class MeatEatingReptile : Reptile, IHuntable
{
abstract void DigestCrayfFish();
...
}
Sealed classes
Using inheritance is not always easy and you have to think everything out
before you start coding. If you create an interface or an abstract class, you
know you are writing something that will be inherited from in the future.
However, it’s hard to predict the future structure. You will need a solid
understanding of the problem that you are modelling. Unless you deliberately
design a class with the purpose of using it as a base class, it’s most unlikely
that it will function well as a base class. With C#, you can use the sealed
keyword to prevent a class from being used as a base class if you decide that it
should not be. For example:
sealed class Alligator : MeatEatingReptile, IWaterBased
{

}

If any class attempts to use Alligator as a base class, a compile-time error will
be generated. Note: a sealed class can’t declare any virtual methods and an
abstract class can’t be sealed.
Sealed methods
You can utilise the the sealed keyword to specify that an individual method in
an unsealed class is sealed. For example, if a derived class can’t override this
method. You can only seal an override method, and you declare the method as
sealed override. A quick way to compare interface, virtual, override, and
sealed keywords is as follows:
The Interface introduces the name of a method.
A virtual method is the initial implementation of a method.
An override method is additional implementation of a method.
A sealed method is the final implementation of a method.
Garbage collection
Each time you create a new object, the common language runtime (CLR) allots
memory for the object from the managed heap. As long as address space is
available in the managed heap, the runtime continues to allocate space for new
objects. Still, memory is not endless. Ultimately the garbage collector (or
G.C.) must perform a collection to free some memory. The G.C. regulates the
best time to perform a collection, based upon the allocations being made. In
order to make a collection the G.C checks for objects in the managed heap that
are no longer being utilised and makes the necessary operations to reclaim
their memory.
Object lifetime
When value types go out of scope they are destroyed and their memory take
back. However, with reference types, you start off creating an object by using
the new operator. The subsequent example creates a new instance of the
Square class
Square mySquare = new Square(); // Square is a reference type
From your point of view, the new operation is a solitary operation, but
underneath, object creation is really a two-phase process:
1. The new operation allocates a chunk of raw memory from the heap.
You have no control over this phase of an object’s creation.
2. The new operation converts the lump of raw memory to an object; it
has to initialize the object. You can regulate this stage by using a
constructor.
After you have created an object, you can access its members by utilising the
dot operator. For example, the Square class includes a method named Draw
that you can call:
mySquare.Draw();
When the mySquare variable goes out of scope, the Square object is no longer
being actively referenced, and the object can be destroyed and the memory that
it is using can be reclaimed (this might not happen immediately). Like object
creation, object destruction is a two-phase process. The two phases of
destruction exactly mirror the two phases of creation:
1. The Common Language Runtime (CLR) must perform some tidying up.
You may control this by writing a destructor.
2. The CLR must return the memory previously belonging to the object
back to the heap; the memory that the object lived in must be
deallocated. You have no control.
Garbage collection is this process of destryong an object and returning the
memory to the heap.
Writing destructors
You can utilise a destructor to complete any tidying up needed when an object
is garbage collected. The CLR will automatically clear up any managed
resources that an object uses, and in many of these cases, writing a destructor
is unnecessary. However, if a managed resource is large (such as a
multidimensional array), it might make sense to make this resource available
for immediate disposal by setting any references that the object has to this
resource to null. Additionally, if an object references an unmanaged resource,
either directly or indirectly, a destructor can prove useful.
A destructor is a special method, a little like a constructor, except that the CLR
calls it after the reference to an object has disappeared. A destructor begins
with the tilde (~) letter then name of class. For example, here’s a simple class
which opens a file for reading in its constructor and closes the file in its
destructor (note that this is simply an example, and I do not recommend that
you always follow this pattern for opening and closing files):

class ProcessFile
{
FileStream file = null;
public ProcessFile(string fileName)
{
this.file = File.OpenRead(fileName); // The file is open for reading
}
~ProcessFile()
{
this.file.Close(); // The file is closed
}
}

There are some very important restrictions that apply to destructors:


Destructors apply only to reference types, i.e. you can’t declare a
destructor in a value type, like a struct for example.
You cannot specify an access modifier (such as public) for a destructor.
You never call the destructor in your own code; part of the CLR called
the G.C. does this for you.
A destructor cannot take any parameters. Again, this is because you
never call the destructor yourself.
Internally, the C# compiler automatically translates a destructor into an
override of the Object.Finalize method. The compiler converts this destructor
class ProcessFile
{
~ProcessFile()
{
// code goes here
}
}
//into the following:
class ProcessFile
{
protected override void Finalize()
{
try
{
// your code goes here
}
finally
{
Base.Finalize();
}
}
}

The compiler generates a Finalize method which holds the destructor body in a
try block. It calls the method in the base. This ensures that a destructor always
calls its base class destructor, even if an exception occurs during your
destructor code.
It’s important to note that solely the compiler can render this translation. You
can’t write your own method to override Finalize, and you can’t call Finalize
yourself.
Why use the garbage collector?
You can never destroy an object yourself by using C# code. There just isn’t any
syntax to do it. The CLR will do it for you at a time of its own making. Also,
remember you can also make several reference variables refer to the same
object. In the subsequent code example, the variables myFp and
referenceToMyFp point to the same ProcessFile object:
ProcessFile myFp = new ProcessFile();
ProcessFile referenceToMyFp = myFp;
How many references can you create to an object? As many as you want! This
has an impact on the lifetime of an object. The CLR must cognize of all these
references. If the variable myFp disappears (by going out of scope), other
variables (such as referenceToMyFp) might still exist and the resources used
by the ProcessFile object cannot be reclaimed (the file shouldn’t be closed).
So, the lifetime of an object cannot be tied to a particular reference variable.
An object can be destroyed and its memory made available for reuse only
when all the references to it have disappeared.
You can see that managing object lifetimes is complex, which is why the
designers of C# decided to prevent your code from taking on this
responsibility. If you needed to destroy objects, sooner or later one of the
ensuing circumstances would come up:
You’d forget to destroy the object. This would mean that the object’s
destructor (if it had one) would not be run, tidying up would not occur,
and memory would not be returned back to the heap.
You’d try to destroy an active object and risk the possibility of one or
more variables holding a reference to a destroyed object, known as a
dangling reference. A dangling reference refers either to unused memory
or possibly to a wholly different object that now happens to occupy the
same piece of memory. Either way, the outcome of using a dangling
reference would be undefined at best or a security risk at worst. All bets
would be off.
You’d try to purge the same object more than once. This may or may not
cause a serious error.
These problems are unacceptable in a language like C#, which places
robustness and security high on its list of design goals so the best option is for
the G.C. to destroy objects on your behalf. It ensures that:
Each object will be destroyed, and its destructor will be run. Once a
program ends, all outstanding objects will be destroyed.
Each object will be destroyed exactly once.
Each object will be destroyed solely onces its unreachable—i.e. when
there are no program references to the object.
These guarantees are extremely useful and free you from tedious housekeeping
chores that are easy to get wrong. They afford you the luxury to concentrating
on the logic of the program itself and being more productive.
Garbage collection can be quite a resource consumer, so the CLR collects
garbage only when it needs to (for example, low memory or the size of the
heap has exceeded the system-defined threshold), and then it collects as much
as it can. Carrying out a few large sweeps of memory is more efficient than
lots of small ones.
One feature of the G.C. is that you don’t know, and should not rely upon, the
order in which objects will be destroyed. The last and probably most
important point to note: Destructors don’t run until objects are garbage
collected. Should you decide to write a destructor, you are going to know that
it will be executed, although not when. Consequently, you should on no
occasion write code which depends on destructors running in a particular
sequence or at a specific point in your application.
How the garbage collector works
It runs on its own individual thread and can execute only at certain times—
typically, when your application reaches the end of a method. While it runs,
other threads running in your application will temporarily halt. This is because
the G.C. might need to move objects around and update object references, and
it cannot do this while objects are in use.
The garbage collector (G.C) is a complicated piece of software that is self-
tuning and implements a number of optimizations to try to balance the need to
keep memory available against the requirement to maintain the performance of
the application. The details of the internal algorithms and structures that the
G.C. uses are beyond the scope of this Ebook but at the high level, the steps
that the G.C. takes are as follows:
1. It builds a map of all reachable objects. It ensures this by continually
following reference fields inside objects. The G.C builds this map very
carefully and makes sure that circular references do not cause endless
recursion. Any object not in this map is considered to be unreachable.
2. It examines if any of the unreachable objects has a destructor that needs
to be run (a process called finalization). Any unreachable object that
needs finalization is placed in a special queue termed the freachable
queue (pronounced “F-reachable”).
3. It deallocates the outstanding unreachable objects (i.e. those that don’t
require finalization) by moving the reachable objects down the heap,
thus defragmenting the heap and freeing memory at its top. Once the G.C
moves a reachable object, it updates all references to that object.
4. From here other threads can resume.
5. It finalizes the unreachable objects that require finalization (now in the
freachable queue) by running the Finalize methods on its own thread.
Recommendations
If you write classes that contain destructors it will adds complexity to your
code and to the G.C process and make your program run more slowly. If your
code doesn’t have any destructors, the G.C doesn’t need to place unreachable
objects in the freachable queue and finalize them. Clearly, not doing something
is faster than doing it. Therefore, try to avoid using destructors except when
you really need them; only use them to reclaim unmanaged resources. For
example, consider a using statement instead, as will be described later in this
chapter.
You must be very careful when you write a destructor. Specifically, be aware
that, if your destructor calls further objects, those objects might have already
had their destructor called by the G.C. As noted the order of finalization is not
guaranteed so make sure that destructors do not depend on one another or
overlap one another. For example, don’t have two destructors that attempt to
release the identical resource.
Resource management
On some occasions its best to release a resource in a destructor; some
resources are just too valuable to wait for an unknown length of time until the
G.C. actually releases them. Limited resources such as memory, database
connections, or file handles need to be released, and they need to be released
as soon as practicable. Situations such as these, your only option is to release
the resource yourself. In order to do this, you create a disposal method – e.g. a
method that unambiguously disposes of a resource. Should a class have a
disposal method, then it is viable for you to call it and decide when the
resource is released.
Disposal methods
Take a class such as TextReader which implements a disposal method. It
provides a mechanism to read characters from a sequential stream of input.
The TextReader class contains a virtual method named Close, which closes the
stream. Both The StreamReader class and the StringReader class override the
Close method and originate from TextReader. The subsequent is an example
which reads lines of text from a file by using the StreamReader class and then
displays it on the screen:
TextReader textReader = new StreamReader(filename);
string inputLines;
while ((inputLines = textReader.ReadLine()) != null)
{
Console.WriteLine(inputLines);
}
reader.Close();

The ReadLine method reads the subsequent line of text from the stream into a
string. The ReadLine method returns null if there is nothing left in the stream.
It’s important to call Close when you have finished with reader to release the
file handle and associated resources. However, this example is not exception-
safe. If the call to ReadLine or WriteLine throws an exception it will be
bypassed and the call to Close won’t occur. If this happens often enough, you
will run out of file handles and be unable to open any more files.
Exception-safe disposal
In order to guarantee that a disposal method (e.g. a Close) is always called,
irrespective of whether there is an exception, you can call the disposal method
within a finally block. The following is the previous example coded by using
this technique:
TextReader textReader = new StreamReader(filename);
try
{
string inputLines;
while ((inputLines = textReader.ReadLine()) != null) // Read until
not empty
...
}
finally
{
reader.Close();
}

You can use a finally block but it has some limitations that make it a less than
perfect solution:
It quickly becomes unwieldy if you have to dispose of more than one
resource. (You end up with nested try and finally blocks.)
In some cases, you might need to modify the code to make it fit this
idiom.
It fails to create an abstraction of the solution. This means that the
solution is hard to understand and you must repeat the code everywhere
you need this functionality.
The reference to the resource stays in scope after the finally block. So,
you could accidentally try to use the resource after it has been released.
The using statement is designed to resolve all these problems.
Using and IDisposable interface
The using statement offers a clean mechanism for regulating the lifetimes of
resources. You can create an object, and this object will be destroyed when the
using statement block finishes:
using ( type variable = initialization )
{
StatementBlock
}
The subsequent example is a good way to ensure that your code always calls
Close on a textReader:
using (TextReader textReader = new StreamReader(filename))
{
string inputLines;
while ((inputLines = textReader.ReadLine()) != null)
{
Console.WriteLine(inputLines);
}
}

The IDisposable interface must be implemented by the variable which you


state in the using statement. The IDisposable interface lives in the System
namespace and contains just one method, named Dispose:
namespace System
{
interface IDisposable
{
void Dispose();
}
}

The purpose of a Dispose method is to free any resources used by an object. It


just so happens that the StreamReader class implements the IDisposable
interface, and its Dispose method calls Close to close the stream. You can
employ a using statement as a clean, exception-safe, and robust way to ensure
that a resource is always released. This approach solves all of the problems
that existed in the manual try/finally solution. The solution now:
Scales well if case you need to dispose of numerous resources.
Doesn’t change the logic of the program code.
Abstracts away the problem & avoids repetition.
Is robust. You can’t accidentally reference the variable declared within
the using statement (in this case, lineReader) after the using statement
has ended because it’s not in scope anymore.
Calling the Dispose method from a destructor
When writing your own classes, should you write a destructor or implement
the IDisposable interface so that instances of your class can be managed by a
using statement? A call to a destructor will happen, but you just don’t know
when. On the contrary you know exactly when a call to the Dispose method
happens, but you just can’t be sure that it will actually happen, since it relies
on the developer using your classes remembering to write a using statement.
Nevertheless, it is possible to guarantee that the Dispose method always runs
by calling it from the destructor. This is like a useful backup. You may not
remember to call the Dispose method; however, you can be certain that it is
called even if it’s only when the program terminates. Here’s an example of
how you might implement the IDisposable interface:
class ExampleOfIDispose : IDisposable
{
private Resource limitedResource; // Limited Resource - must manage &
dispose
private bool disposedFlag = false; // Denotes if Limited resource has
// been disposed or not
~ ExampleOfIDispose ()
{
this.Dispose(false);
}
public vrtual void Dspose()
{
this.Dspose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dspose(bool dsposing)
{
if (!ths.disposedFlag)
{
if (disposing)
{
// release the big managed resource here
}
// release the unmanaged resources here

this.disposedFlag = true;
}
}
public void CertainFunction() // Regular code
{
checkIfDisposed();
}
private void checkIfDisposed()
{
if (this.disposedFlag)
{
throw new ObjectDisposedException("ExampleOfIDispose: object has
been disposedFlag of");
}
}
}

Features of the IDispose class:


The IDisposable interface is implemented by this class.
Your application code can call the public Dispose method at any time
by.
The public Dispose method calls the protected and overloaded version
of the Dispose method that takes a Boolean parameter, passing the value
true as the argument. This method actually performs the resource
disposal.
The destructor calls the protected and overloaded version of the
Dispose method that takes a Boolean parameter, passing the value false
as the argument. The destructor is called only by the garbage collector,
when your object is being finalized.
You can call the protected Dispose method safely multiple times. The
variable disposed indicates whether the method has already been run
and is a safety feature to prevent the method from attempting to dispose
the resources numerous times if it is called simultaneously. (Your
application might call Dispose, but before the method completes, your
object might be garbage-collected and the Dispose method run again by
the CLR from destructor.) The resources are released only the first time
the method runs.
The protected Dispose method supports disposal of managed resources
(e.g. large array) and unmanaged resources (e.g. file handle). If the
disposing parameter is true, this method must have been called from the
public Dispose method. In this case, the managed resources and
unmanaged ones are let go. If the disposing parameter is false, this
method must have been called from the destructor, and the G.C. is
finalizing the object. In this case, it is not necessary (or exception safe)
to release the managed resources, because they will be, or have been by
now, handled by the garbage collector, so only the unmanaged resources
are released.
The public Dispose method calls the static GC.SuppressFinalize
method. This method stops the G.C. from calling the destructor on this
object which has formerly been finalized.
All the regular methods of the class (such as CertainFunction) check to
see whether the object has already been discarded. If it has, they throw
an exception.
Part III Extending C# Types
Properties
A property is a cross between a field and a method—it looks like a field but
acts like a method. You access a property by using exactly the same syntax that
you use to access a field. Although the compiler automatically translates that
into accessor methods calls (also know as (property) getters & (property)
setters).
The following outlines how to declare properties:
AccessModifier Type PropertyName
{
get
{
// read - only to find out value information
}
set
{
// write – to make changes
}
}
A property can contain two blocks of code, starting with the get and set
keywords. The get block contains statements that execute when the property is
read, and the set block contains statementsthat run upon writing to the property.
The property type stipulates the type of data read (get accessor) and written
(set accessors).
The subsequent code demonstrates the ScreenPosition structure rewritten by
using properties. When looking at this code, note the following:
Lowercase _a and _b are private fields.
Uppercase PublicA and PublicB are public properties.
All set accessors are sent the data to be written via a hidden, built in
parameter named value.
A private field directly implements each property, but this is only one way to
implement a property. All that is required is that a get accessor returns a value
of the specified type. Such a value can simply be calculated dynamically as
opposed to being simply retrieved from stored data, in which case there would
be no need for a physical field.
struct ScreenPositional
{
private int _a, _b;
public ScreenPositional(int PublicA, int PublicB)
{
this._a = rangeCheckA(PublicA);
this._b = rangeCheckB(PublicB);
}
public int PublicA
{
get { return this._a; }
set { this._a = rangeCheckA(value); }
}
public int PublicB
{
get { return this._b; }
set { this._b = rangeCheckB(value); }
}
private static int rangeCheckA(int a) { . . . }
private static int rangeCheckB(int b) { . . . }
}
Using properties
Once you utilise a property in an expression, you can use it in a read setting
(i.e. you are retrieving its value) and in a write setting (i.e. you are adjusting
its value). The code that follows demonstrates how to read values from the
PublicA and PublicB properties of the ScreenPositional structure:
ScreenPositional originals = new ScreenPositional(0, 0);
int apos = originals.PublicA; // calls originals.PublicA.get
int bpos = originals.PublicB; // calls originals.PublicB.get
You used identical syntax to access properties and field. When you utilise a
property in a read context, the compiler automatically translates your field-like
code into a call to the get accessor of that property. Likewise, if you use a
property in a write context, the compiler automatically translates your field-
like code into a call to the set accessor of that property.
originals.PublicA = 20; // calls originals.PublicA.set, with value set to 20
originals.PublicB = 150; // calls originals.PublicB.Set, with value set to 150
The values being assigned are passed in to the set accessors by using the value
variable, as described in the preceding section. The runtime performs this task
straight away.
You can also utilise a property in a read/write setting. In such a circumstance,
both the get accessor & set accessor are utilised. For example, the compiler
automatically translates statements such as the following into calls to the get
and set accessors:
originals.PublicA += 10;
Read only properties
It is possible to declare a property which encompasses only a get accessor. In
such a case, you may utilise the property solely in a read context. For example,
here’s the PublicA property of the ScreenPositional structure declared as a
read-only property:

struct ScreenPositional
{
private int _a;
...
public int PublicA
{
get { return this._a; }
}
}

The PublicA property does not contain a set accessor; therefore, any attempt to
use PublicA in a write context will fail, as demonstrated in the subsequent
example:
originals.PublicA = 170; // compile-time error
Write-only properties
Likewise, it is possible to declare a property that contains only a set accessor.
In this case, you can utilise the property only in a write context. For example,
here’s the X property of the ScreenPositional structure declared as a write-
only property:
struct ScreenPositional
{
private int _a;
...
public int PublicA
{
set { this._a = rangedCheckedA(value); }
}
}

The PublicA property does not contain a get accessor; any attempt to use
PublicA in a read context will fail, as illustrated here:
Console.WriteLine(originals.PublicA); // This results in a compile error
originals.PublicA = 200; // This compiles fine
originals.PublicA += 10; // This results in a compile error
Property accessibility
It is feasible to stipulate the properties accessibility (public, private, or
protected) when you declare it. However, it is possible within the property
declaration to override the property accessibility for the get and set accessors.
Take the version of the ScreenPositional structure for example shown below, it
defines the set accessors of the PublicA and PublicB properties as private.
(The get accessors are public, since the properties are public.)
struct ScreenPositional
{
private int _a, _b;
...
public int PublicA
{
get { return this._a; }
private set { this._a = rangeCheckedA(value); }
}
public int PublicB
{
get { return this._b; }
private set { this._b = rangeCheckedB(value); }
}
...
}
You must observe some rules when defining accessors with different
accessibility from one another:
You can change the accessibility of only one of the accessors when you
define it. This is so since it is not logical to define a property as public
and then change the accessibility of both properties to private later.
The modifier can’t stipulate lesser restrictive accessibility than that of
the property. Take the property as declared private for example, you
can’t specify the read accessor as public. (Instead, you would make the
property public and make the write accessor private.)
Property restrictions
Properties look, act, and feel like fields when you read or write data using
them. However, they are not true fields, and certain restrictions apply to them:
You can assign a value through a property of a structure or class only
after the struc & class has been created. The following code example is
illegal because the location variable has not been initialized (by using
new):
ScreenPositional location;
location.PublicA = 20; // compile-time error, location not assigned
You can’t use a property as a ref or an out argument to a method
(although you can use a writable field as a ref or an out argument). This
makes sense because the property doesn’t really point to a memory
location; rather, it points to an accessor method, such as in the following
example:
MyMethod(ref location.PublicA); // compile-time error
At most a property, can contain is one get accessor and one set accessor.
It can’t contain other methods, fields, or properties.
The get and set accessors cannot take any parameters. The data being
assigned is passed to the set accessor automatically by using the value
variable.
You can’t declare const properties, such as is demonstrated here:
const int PublicA { get { . . . } set { . . . } } // compile-time error
Indexers
You can think of an indexer as a smart array in much the same way that you can
think of a property as a smart field. Whereas a property encapsulates a single
value in a class, an indexer encapsulates a set of values. The syntax for an
indexer is identical to that of an array. They are invaluable if you want to
provide access to items that contain multiple values by using a natural and
familiar syntax. Points to note on indexers are:
Indexers allow objects to be indexed in a comparable way to arrays.
You return a value with the get accessor and assign a value with the set
accessor.
You utilise this keyword to state the indexers.
Utilise the value keyword to define the value being assigned by the set
indexer
You don’t have to use integer values to index Indexers; its your
obligation to state the precise look-up mechanism.
You can overload Indexers.
You can use more than one formal parameter, e.g. accessing a two-
dimensional array.

An example which doesn’t use indexers


Usually you use an int to store an integer value. Internally, an int stores its
value as a sequence of 32 bits, where each bit can be either 0 or 1. Most of the
time, you don’t care about this internal binary representation; you just use an
int type as a container that holds an integer value. However, sometimes
programmers use the int type for other purposes—some programs use an int as
a set of binary flags and manipulate the individual bits within an int.
C# provides a set of operators that you can use to access and manipulate the
individual bits in an int. These include:
The NOT (~) operator A unary operator which performs a bitwise
complement. Forexample, if you take the 8-bit value 11001100 (204
decimal) and apply the ~ operator to it, you obtain the result 00110011
(51 decimal)—all the 1s in the original value become 0s, andall the 0s
become 1s.
The left-shift (<<) operator This is a binary operator that performs a
left shift. The expression 204 << 2 give the result 48. (In binary, decimal
204 equals 11001100, & left shifting it by 2 places makes 00110000, or
48 decimal.) The far-left bits are discarded, and zeros are introduced
from the right. There is a corresponding right-shift operator, >>.
The OR (|) operator This is a binary operator that performs a bitwise
OR operation, returning a value containing a 1 in each position in which
either of the operands has a 1. Take the expression 204 | 24 for example,
it has the value 220 (204 is 11001100, 24 is 00011000, and 220 is
11011100).
The AND (&) operator This operator performs a bitwise AND
operation. AND is similar to the bitwise OR operator, except that it
returns a value containing a 1 in each position where both of the
operands have a 1. So, 204 & 24 is 8 (204 is 11001100, 24 is
00011000, and 8 is 00001000).
The XOR (^) operator This operator completes a bitwise exclusive
OR operation. That is, returning 1 in every bit where there is a 1 in one
operand or the other, but not both. (Two 1s yield a 0 which is the
“exclusive” part of the operator.) Therefore 204 ^ 24 is 212 (11001100 ^
00011000 is 11010100).
You can utilise these operators together to determine the values of the specific
bits in an int. As an example, the following expression uses the left-shift (<<)
and bitwise AND (&) operators to determine whether the sixth bit from the
right of the byte variable named bits is set to 0 or to 1:
(bits & (1 << 5)) != 0
Suppose that the bits variable contains the decimal value 42. In binary, this is
00101010. The decimal value 1 is 00000001 in binary, and the expression 1
<< 5 has the value 00100000; the sixth bit is 1. In binary, the expression bits &
(1 << 5) is 00101010 & 00100000, and the value of this expression is binary
00100000, which is nonzero. If the variable bits contain the value 65, or
01000001 in binary, the value of the expression is 01000001 & 00100000,
which yields the binary result 00000000, or zero.
This is a fairly complicated example, but it’s trivial in comparison to the
following expression, which uses the compound assignment operator &= to set
the bit at position 6 to 0:
bits &= ~(1 << 5)
Similarly, if you want to set the bit at position 6 to 1, you can use a bitwise OR
(|) operator. The following complicated expression is based on the compound
assignment operator |=:
bits |= (1 << 5)
The trouble with these examples is that although they work, they are not at all
easy to comprehend. They’re complicated, and the solution is a very low-level
one: it fails to create an abstraction of the problem that it solves, and it is
consequently very difficult to maintain code which carries out these kinds of
operations.

The same example using indexers


Let’s pull back from the preceding low-level solution for a moment for a
reminder of what the problem is. You’d like to use an int not as an int but as an
array of bits. Therefore, the best way to solve this problem is to use an int as if
it were an array of bits; in other words, what you’d like to be able to write to
access the bit 6 places from the right in the bits variable is an expression such
as the following (remember that arrays start with index 0):
bits[5]
And, to set the bit 4 places from the right to true, we’d like to be able to write
this:
bits[3] = true
Unfortunately, you can’t use the square bracket notation on an int; it works only
on an array or on a type that behaves like an array. The answer to the problem
is to make a new type that is essentially like an array of bool variables but is
implemented by using an int. You can achieve this feat by defining an indexer.
Let’s call this new type IntegerBits. IntegerBits will contain an int value
(initialized in its constructor), but the idea is that you’ll use IntegerBits as an
array of bool variables.
struct IntegerBits
{
private int bits;
public IntegerBits(int initialBitValue)
{
bits = initialBitValue;
}
// indexer to be written here
}

To define the indexer, you use a notation that is a cross between a property and
an array. You introduce the indexer with the this keyword, specify the type of
the value returned by the indexer, and also specify the type of the value to use
as the index into the indexer amongst [] square brackets. The indexer for the
IntegerBits struct uses an integer as its index type and returns a Boolean value:
struct IntegerBits
{
public bool this[int bitIndex]
{
get
{
return (bits & (1 << bitIndex)) != 0;
}
set
{
if (value) // If the value is true turn the bit on
bits |= (1 << bitIndex);
else // else turn it off
bits &= ~(1 << bitIndex);
}
}
}

Note the following:


Although similar an indexer isn’t a method. It has no parentheses
containing a parameter, however there are square brackets that stipulate
an index. You utilise this bitIndex to specify which element are being
accessed.
Each indexer utilises the this keyword. A struct or class may state at
most one indexer (however it is possible to overload it & have
numerous implementations). Plus it is always named this.
Indexers encompass get and set accessors comparable to properties. The
get & set accessors here have the intricate bitwise expressions
(discussed previously).
The index stated in the indexer assertion is furnished with the index
value stated once the indexer was called. The get and set accessor
methods can read this argument to decide which element should be
accessed.

Understanding indexer accessors


Whenever you read an indexer, the compiler immediately translates your array-
like code into a call to the get accessor of that indexer. For example:
bool peek = bits[6];
This line of code is converted to a call to the get accessor for bits, and the
index argument is set to 6.
Likewise, if you write to an indexer, the compiler automatically translates your
array-like code into a call to the set accessor of that indexer, setting the index
argument to the value enclosed in the square brackets, such as demonstrated
here:
bits[3] = true;
This statement is converted to a call to the set accessor for bits where index is
3. Like ordinary properties, the data which you are writing to the indexer (in
this case, true) is made available inside the set accessor by using the value
keyword. The type of value is identical to the type of indexer itself (bool in
this example).
It’s also possible to use an indexer in a combined read/write context. In such a
circumstance, the get and set accessors are both used. The following for
example uses the XOR operator (^) to invert the value of the bit at index 6 in
the bits variable:
bits[6] ^= true;
This code is automatically translated into the following:
bits[6] = bits[6] ^ true;
This code works for the reason that the indexer declares both a get and a set
accessor.
Comparing indexers and arrays
When you use an indexer, the syntax is purposely array-like. Although, there
are numerous significant differences between indexers and arrays:
Indexers can utilise non-numeric subscripts, like string as shown in the
subsequent example, while arrays can only use integer subscripts.
public int this[string name] { . . . } // This is ok
You can overload Indexers (like methods). However, arrays can’t.
public Name this[PhoneNumber number] { . . . }
public PhoneNumber this[Name name] { . . . }
You cannot use Indexers as ref or out parameters, while array elements
can be.
IntegerBits bits; // bits contains an indexer
Method(ref bits[1]); // compile-time error
Indexers in interfaces
You can declare indexers in an interface. To acheive this, stipulate the get
keyword, the set keyword, or both, but substitute the body of the get or set
accessor with a semicolon. Every class or structure which implements the
interface needs to implement the indexer accessors declared in the interface, as
shown here:
interface IUntreatedInt
{
bool this[int bitIndex] { get; set; }
}

struct UntreatedInt : IUntreatedInt


{

public bool this[int bitIndex]


{
get { . . . }
set { . . . }
}

Should you implement the interface indexer in a class, you can state the indexer
implementations as virtual. This permits further derived classes to override the
get and set accessors, like so:
class UntreatedInt : IUntreatedInt
{
...
public virtual bool this[int bitIndex]
{
get {}
set {}
}
...
}
Generics
Once your applications start to develop and become more sophisticated, you
are going to require a better way to reuse and modify existing software. C#
includes a feature called generics to facilitate code reuse, especially the reuse
of algorithms. Just as methods are powerful because they can take arguments,
so types and methods that take type arguments have significantly more
functionality.
C# without generics
So far in this Ebook you have seen that you can use the object type to store a
value of any type, and you can define parameters by using the object type when
you have to pass values of any type into a method. You can also return values
of any time with a method and this practice is very flexible but it has a
drawback. The responsibility on the developer to remember what kind of data
is being used. If the developer makes a mistake this can result in run time
errors.
In order to understand generics, its best to look in detail at the problem that
they are designed to solve. For example, presuppose that you needed to model
a first in, first out structure such as a queue. You could create a class such as
the following:
using System;
class Queue
{
private const int DEFAULTSIZEOFQUEUE = 200;
private int[] dataQueue;
private int headz = 0, tailz = 0;
private int numbElements = 0;
public Queue()
{
this.dataQueue = new int[DEFAULTSIZEOFQUEUE];
}
public Queue(int size)
{
if (size > 0)
{
this.dataQueue = new int[size];
}
else
{
throw new ArgumentOutOfRangeException("size", "Needs be larger than
zero!");
}
}

public void Enqueue(int item)


{
if (this.numbElements == this.dataQueue.Length)
{
throw new Exception("The Queue is full!");
}
this.dataQueue[this.headz] = item;
this.headz++;
this.headz %= this.dataQueue.Length;
this.numbElements++;
}

public int Dequeue()


{
if (this.numbElements == 0)
{
throw new Exception("The Queue is empty!");
}
int queueItem = this.dataQueue[this.tailz];
this.tailz++;
this.tailz %= this.dataQueue.Length;
this.numbElements--;
return queueItem;
}

This class uses an array to provide a circular buffer for holding the data. The
size of this array is specified by the constructor. An application uses the
Enqueue method to add an item to the queue and the Dequeue method to pull an
item off the queue. Where to insert, retrieve an item from the array is kept
track of with the private head and tail fields. The numElements field indicates
how umteen items are in the array. The Enqueue and Dequeue methods use
these fields to determine where to store or retrieve an item from and perform
some rudimentary error checking. An application can generate a Queue object
and call these methods, as illustrated in the code example that follows. Notice
that the items are dequeued in the same order in which they are enqueued:
Queue queue = new Queue(); // Creates a new Queue
queue.Enqueue(200);
queue.Enqueue(-50);
queue.Enqueue(27);
Console.WriteLine("{0}", queue.Dequeue()); // Displays 200
Console.WriteLine("{0}", queue.Dequeue()); // Displays -50
Console.WriteLine("{0}", queue.Dequeue()); // Displays 27
Now, the Queue class works well for queues of ints, but what if you want to
create queues of strings, or floats, or even queues of more complex types such
as Circle (as covered in “Classes and objects”), or Alligator, or Whale? The
problem is that the way in which the Queue class is implemented restricts it to
items of type int, and if you try to enqueue a Alligator, you will get a compile-
time error.
Queue queue = new Queue();
Alligator myAlligator = new Alligator();
queue.Enqueue(myAlligator); // Compile time error Can't convert from
Alligator to integer
One way around this restriction is to specify that the array in the Queue class
contains items of type object, update the constructors, and modify the Enqueue
and Dequeue methods to take an object parameter and return an object, such as
in the following:

class Queue
{
...
private object[] datum;
...
public Queue()
{
this.datum = new object[DEFAULTQUEUESIZE];
}
public Queue(int size)
{
...
this.datum = new object[size];
...
}
public void Enqueue(object item)
{
...
}
public object Dequeue()
{
...
object queueItem = this.datum[this.tail];
...
return queueItem;
}
}

Don’t forget that you can utilise the object type to refer to a value or variable
of any type. Every reference type inherit from the System.Object class in the
.NET Framework automatically (C#: object a.k.a System.Object). Now,
because the Enqueue and Dequeue methods manipulate objects, you can
operate on queues of Circles, Alligators, Whales, or any of the other classes
that you have seen in earlier exercises in this Ebook. Although, it is vital to
note that you must cast the value returned by the Dequeue method to the
appropriate type since the compiler won’t perform the conversion from the
object type automatically.
Queue queue = new Queue();
Alligator myAlligator = new Alligator();
queue.Enqueue(myAlligator); // Now legal – Alligator is an object
Queue queue = new Queue();
Alligator myAlligator = new Alligator();
queue.Enqueue(myAlligator); // This is ok – Alligator is now an object
...
Alligator dequeuedAlligator = (Alligator)queue.Dequeue(); // Must cast object
back to a Alligator
If you don’t cast the returned value, you will get the compiler error “Cannot
implicitly convert type ‘object’ to ‘Alligator.’” This requirement to perform an
explicit cast degenerates much of the flexibility afforded by the object type.
Furthermore, it is very easy to write code such as this:
Queue queue = new Queue();
Alligator myAlligator = new Alligator();
queue.Enqueue(myAlligator);
...
Circle myCircle = (Circle)queue.Dequeue(); // run-time error
Although this code will compile, it is not valid and throws a
System.InvalidCastException exception at run time. The error is caused by
trying to store a reference to an Alligator in a Circle variable when it is
dequeued, and the two types are not compatible. The compiler will not throw
an error because it doesn’t have information to perform this check at compile
time. The real type of the object being dequeued becomes apparent only when
the code runs.
Another disadvantage of using the object approach to create generalized
classes and methods is that it can consume additional memory and processor
time should the runtime require to convert an object type to value type & back
to object type again . Consider the following piece of code that manipulates a
queue of int values:
Queue queue = new Queue();
int myInteger = 99;
queue.Enqueue(myInteger); // box the integer to an object
...
myInteger = (int)queue.Dequeue(); // unbox the object to an integer
The Queue data type assumes the items it holds to be objects (reference type).
Enqueueing a value type, like as an int, necessitates it to be boxed in order to
convert it to a reference type. Likewise, dequeueing into an int means the item
has to be unboxed to converted back to a value type. Although boxing and
unboxing happen transparently, they add performance overhead because they
involve dynamic memory allocations. Although the overhead is small for each
item, it all starts to adds up when a program queues large numbers of value
types.
C# with generics
C# provides generics to remove the need for casting, improve type safety,
reduce the amount of boxing required, and make it easier to create generalized
classes and methods. Generic classes and methods accept type parameters,
which specify the types of objects on which they operate. In C#, you indicate
that a class is a generic class by providing a type parameter in angle brackets,
like this:
class Queue<T>
{
...
}
The T in the above example is like a container for a real type at compile time.
When you write code to instantiate a generic Queue, you provide the type that
should be substituted for T (Circle, Alligator, int, and so on). When you define
the fields and methods in the class, you use this same placeholder to indicate
the type of these items, like this:

class Queue<T>
{
...
private T[] datum; // array is of type 'T' where 'T' is the type parameter
...
public Queue()
{
this.datum = new T[DEFAULTQUEUESIZE]; // utilise 'T' as the data
type
}
public Queue(int size)
{
...
this.datum = new T[size];
...
}
public void Enqueue(T item) // utilise 'T' as method type parameter
{
...
}
public T Dequeue() // utilise 'T' as return type value
{
...
T queueItem = this.datum[this.tail]; // the data in the array is of type 'T'
...
return queueItem;
}

The type parameter T can be any legal C# identifier, although the lone
character T is commonly used. It is replaced with the type you specify when
you create a Queue object. The subsequent examples create a Queue of ints,
and a Queue of Alligators:
Queue<int> intQueueExample = new Queue<int>();
Queue<Alligator> AlligatorQueue = new Queue<Alligator>();
Additionally, the compiler now has enough information to perform strict type-
checking when you build the application. You no longer need to cast data when
you call the Dequeue method, and the compiler can trap any type mismatch
errors early:
intQueueExample.Enqueue(99);
int myInt = intQueueExample.Dequeue(); // no casting necessary
Alligator myAlligator = intQueueExample.Dequeue(); // compiler error:
// cannot implicitly convert type 'int' to
'Alligator'
You should be aware that this substitution of T for a specified type is not
simply a textual replacement mechanism. Rather, the compiler completes a
complete semantic substitution in order for you to specify any valid type for T.
Here are more examples:
struct Person
{
...
}
...
Queue<int> intQueueExample = new Queue<int>();
Queue<Person> personQueue = new Queue<Person>();

The first example produces a queue of integers while the second example
creates a queue of Person values. The compiler also generates the versions of
the Enqueue and Dequeue methods for each queue. The methods for the
intQueueExample queue look like the following:
public void Enqueue(int item);
public int Dequeue();

The methods for personQueue queue, are:


public void Enqueue(Person item);
public Person Dequeue();

Contrast these definitions with those of the object-based version of the Queue
class shown in the preceding section. In the methods derived from the generic
class, the item parameter to Enqueue is passed as a value type (no boxing
need). Similarly, the value returned by Dequeue is also a value type that does
not need to be unboxed. A similar set of methods is generated for the other two
queues.
The type parameter don’t have to be a simple class or value type. For example,
you can create a queue of queues of integers (if you should ever find it
necessary), like this:
Queue<Queue<int>> queueQueue = new Queue<Queue<int>>();
A generic class can have multiple type parameters. For illustration, the
generic Dictionary class defined in the System.Collections.Generic namespace
in the .NET Framework class library assumes two type parameters: one type
for keys, one for values.
Collections
You have to create and manage groups of related objects for numerous
applications. You can group objects in two ways (1) generating arrays of
objects, (2) generating collections of objects. Collections offer a more supple
way to work with groups of objects. As opposed to arrays, the group of objects
can grow & shrink dynamically when the needs of the application change. For
some collections, you may assign a key to any object which you put into the
collection so that you can quickly recover the object by using the key.
The subsequent table is a list of the most generally used collections.
Collection Description
List<T>
List of
objects - accessible by index, like an
array, but with addi​tional methods to
search list & sort the contents of list.

Queue<T>
First in,
first out data structure, with methods to
add an entity to one end of the queue,
remove an entity from the other end, &
inspect an entity short of removing it.

Stack<T>
First in,
last out data structure with methods to
push an entity onto the top of the stack,
pop an entity from the top of the stack,
& inspect the entity at the top of the
stack short of removing it.

LinkedList<T>
Double ended
ordered list, adjusted to sustain
insertion & removal at either end.
Possible to act like a queue or a stack,
but in addition supports random access
like a list.

HashSet<T>
Unordered
set of values which is adjusted for
quick recovery of data. It provides set
oriented methods for establishing
whether the entities it holds are a subset
of those in another HashSet<T> object
as well as computing the intersection &
union of HashSet<T> objects.

Dictionary<TKey, TValue>
Collection of values which
can be identified & retrieved by using
keys rather than indexes.
SortedList<TKey, TValue>
Sorted key/value pairs list.
Keys are required to implement
IComparable<T>.
The List<T> collection class
The generic List<T> class is the simplest of the collection classes. You can
utilise it much like an array—you can reference a present element in a List<T>
collection by using ordinary array notation, with square brackets and the index
of the element, however you can’t utilise array notation to increase new
elements. However, in general, the List<T> class provides more flexibility
than arrays and is designed to overcome the following restrictions exhibited by
arrays:
To readjust an array, you must create a new array, copy the elements
To remove an element from an array, you must move all the trailing
elements up by one place.
To insert an element into an array, you must move elements down by one
place to make a free slot. However, you lose the last element of the
array!
The List<T> collection class provides the following features:
You don’t need to specify the capacity of a List<T> collection when you
create it.
To remove a specified element from a List<T> collection use the
Remove method.
You can utilise the add method to add an element at end of List<T>
collection.
You can utilise the insert method in order to insert an item in to the
central part of a List<T> collection.
To easily sort the data in a List<T> object call the Sort method.
The following is an example which illustrates how to create, manipulate, and
iterate through the contents of a List<int> collection:
...
List<int> sampleNumbers = new List<int>();
// Fill the List<int> by using the Add method
foreach (int number in new int[12]{10, 9, 8, 7, 7, 6, 5, 10, 4, 3, 2, 1})
{
sampleNumbers.Add(number);
}
// Insert an element in the penultimate position in the list & move last entity up
// The first parameter is the position; the second parameter is the value being
inserted
sampleNumbers.Insert(sampleNumbers.Count-1, 99);
// Remove first element whose value is 7 (the 4th element, index 3)
sampleNumbers.Remove(7);
// Remove the element that's now the 7th element, index 6 (10)
sampleNumbers.RemoveAt(6);
// Iterate remaining 11 elements using a for statement
Console.WriteLine("Iterating using a for statement:");
for (int i = 0; i<sampleNumbers.Count; i++)
{
int number = sampleNumbers[i]; // Note the use of array syntax
Console.WriteLine(number);
}
// Iterate the same 11 elements using a foreach statement
Console.WriteLine("\nIterating using a foreach statement:");
foreach (int number in sampleNumbers)
{
Console.WriteLine(number);
}
Here is the output of this code:
Iterating using a for statement: 10 9 8 7 6 5 4
The LinkedList<T> collection class
Each item in the list holds the value for the item together with a reference to the
next item in the list (the Next property) and the previous item (the Previous
property). The item at the commencement of the list has the preceding property
set to null, and the item at the conclusion of the list has the Next property set to
null.
Unlike the List<T> class, LinkedList<T> does not support array notation for
inserting or examining elements. Instead, you can use the AddFirst method to
insert an element at the start of the list, moving the first item up and setting its
Previous property to refer to the new item, or the AddLast method to insert an
element at the end of the list, setting the Next property of the previously last
item to refer to the new item. You can also use the AddBefore and AddAfter
methods to insert an element before or after a specified item in the list (you
have to retrieve the item first).
You can find the first item in a LinkedList<T> collection by querying the First
property, whereas the Last property returns a reference to the final item in the
list. To iterate through a linked list, you can start at one end and step through
the Next or Previous references until you find an item with a null value for this
property. Alternatively, you can use a foreach statement, which iterates
forward through a LinkedList<T> object and stops automatically at the end.
You delete an item from a LinkedList<T> collection by using the Remove,
RemoveFirst, and RemoveLast methods.
The subsequent code shows a working LinkedList<T> collection. Notice how
the code that iterates through the list by using a for statement steps through the
Next (or Previous) references, only stopping once it recieves a null:
...
List<int> sampleNumbers = new List<int>();
// Fill the List<int> by using the Add method
foreach (int number in new int[12]{10, 9, 8, 7, 7, 6, 5, 10, 4, 3, 2, 1})
{
sampleNumbers.Add(number);
}
// Insert an element in the penultimate position in the list & move the last item
up
// The 1st parameter is the position; the 2nd parameter is the value being
inserted
sampleNumbers.Insert(sampleNumbers.Count-1, 99);
// Get rid of first element whose value is 7 (the 4th element, index 3)
sampleNumbers.Remove(7);
// Get rid of the element that's now the 7th element, index 6 (10)
sampleNumbers.RemoveAt(6);
// Iterate remaining 11 elements using a for statement
Console.WriteLine("Iterating using a for statement:");
for (int i = 0; i<sampleNumbers.Count; i++)
{
int number = sampleNumbers[i]; // Note the use of array syntax
Console.WriteLine(number);
}
// Iterate the same 11 elements using a foreach statement
Console.WriteLine("\nIterating using a foreach statement:");
foreach (int number in sampleNumbers)
{
Console.WriteLine(number);
}
The following is outputted to the console:
Iterating using a for statement: 2 4 6 8 10
Iterating using a foreach statement: 2 4 6 8 10
Iterating list in reverse order: 10 8 6 4 2
The Queue<T> collection class
The Queue<T> class implements a first in, first out (FIFO) mechanism. The
Enqueue operation adds and item to the back of the queue while the Dequeue
operation takes the item off queue at the front.
Here follows an example showing a Queue<int> collection and its usual
operations:
using System;
using System.Collections.Generic;
...
Queue<int> sampleNumbers = new Queue<int>();
// fill up the queue with items
Console.WriteLine("Populating the queue:");
foreach (int number in new int[4]{8, 5, 6, 1})
{
sampleNumbers.Enqueue(number);
Console.WriteLine("{0} has joined the queue", number);
}
// iterate through the queue
Console.WriteLine("\nThe queue contains the following items:");
foreach (int number in sampleNumbers)
{
Console.WriteLine(number);
}
// remove all items from the queue
Console.WriteLine("\nDraining the queue:");
while (sampleNumbers.Count > 0)
{
int number = sampleNumbers.Dequeue();
Console.WriteLine("{0} has left the queue", number);
}

Here is the output from this code:


Populating the queue:
9 has joined the queue
3 has joined the queue
7 has joined the queue
2 has joined the queue
The queue contains the following items: 9 3 7 2
Draining the queue:
9 has left the queue
3 has left the queue
7 has left the queue
2 has left the queue
The Stack<T> collection class
It is class modelled on a LIFO mechanism. An element joins the stack at the top
(the push operation) and leaves the stack at the top (the pop operation). Here’s
an example—notice the order in which the items are listed via foreach loop:
using System;
using System.Collections.Generic;
...
Stack<int> sampleNumbers = new Stack<int>();
// fill the stack
Console.WriteLine("Pushing items onto the stack:");
foreach (int number in new int[4]{8, 5, 6, 1})
{
sampleNumbers.Push(number);
Console.WriteLine("{0} has been pushed on the stack", number);
}
// iterate through the stack
Console.WriteLine("\nThe stack now contains:");
foreach (int number in sampleNumbers)
{
Console.WriteLine(number);
}
// empty the stack
Console.WriteLine("\nPopping items from the stack:");
while (sampleNumbers.Count > 0)
{
int number = sampleNumbers.Pop();
Console.WriteLine("{0} has been popped off ", number);
}
Here is the output from this program:
Pushing items onto the stack:
9 has been pushed on the stack
3 has been pushed on the stack
7 has been pushed on the stack
2 has been pushed on the stack
The stack now contains: 2 7 3 9
Popping items from the stack:
2 has been popped off
7 has been popped off
3 has been popped off
9 has been popped off
The Dictionary<TKey, TValue> collection class
The array and List<T> types provide a way to map an integer index to an
element. You specify an integer index within square brackets (for example,
[4]), and you get back the element at index 4 (which is actually the fifth
element). However, sometimes you might want to implement a mapping in
which the type from which you map is not an int but rather some other type,
such as string, double, or Time. The Dictionary<TKey, TValue> class
implements this functionality by internally maintaining two arrays, one for the
keys from which you’re mapping and one for the values to which you’re
mapping. When you insert a key/value pair into a Dictionary<TKey, TValue>
collection, it automatically tracks which key belongs to which value and makes
it possible for you to retrieve the value which is linked with a specified key
quickly and effortlessly. The design of the Dictionary<TKey, TValue> class
has some important consequences:
A Dictionary<TKey, TValue> collection cannot contain duplicate keys.
If you call the Add method to add a key that is already present in the
keys array, you’ll get an exception. You can, however, use the square
brackets notation to add a key/value pair (as shown in the following
example), without danger of an exception, even if the key has already
been added; any present value with the identical key will be overwritten
with the new value. You can test if a Dictionary<TKey, TValue>
collection already contains a particular key by using the ContainsKey
method.
Internally, a Dictionary<TKey, TValue> collection is a sparse data
structure that operates most efficiently when it has plenty of memory
with which to work. A Dictionary<TKey, TValue> collection can get
really big when you add more items.
When you use a foreach statement to iterate through a Dictionary<TKey,
TValue> collection, you get back a KeyValuePair<TKey, TValue> item.
This is a structure that contains a copy of the key and value elements of
an item in the Dictionary<TKey, TValue> collection, and you can access
each element through the Key property and the Value properties. These
elements are read-only; you cannot use them to modify the data in the
Dictionary<TKey, TValue> collection.
An example that associates the ages of members of my family with their names
and then prints the information:
using System;
using System.Collections.Generic;
...
Dictionary<string, int> ages = new Dictionary<string, int>();
// fill the Dictionary
ages.Add("Luis", 47); // using the Add method
ages.Add("Rossanna", 46);
ages["Joelle"] = 20; // using array notation
ages["Jannett"] = 18;
// iterate using a foreach statement, the iterator generates a KeyValuePair item
Console.WriteLine("The Dictionary has:");
foreach (KeyValuePair<string, int> element in ages)
{
string names = element.Key;
int age = element.Value;
Console.WriteLine("Name: {0}, Age: {1}",names,age);
}
Here is the output from this program:
The Dictionary contains:
Name: Luis, Age: 47
Name: Rossanna, Age: 46
Name: Joelle, Age: 20
Name: Jannett, Age: 18
The SortedList<TKey, TValue> collection class
The SortedList<TKey, TValue> class is very similar to the Dictionary<TKey,
TValue> class in that you can use it to associate keys with values. The main
difference is that the keys array is always sorted. (It is called a SortedList,
after all.) It takes longer to insert data into a SortedList<TKey, TValue> object
than a SortedDictionary<TKey, TValue> object in most cases, but data
retrieval is often quicker (or at least as quick), and SortedList<TKey, TValue>
class uses less memory.
When you insert a key/value pair into a SortedList<TKey, TValue> collection,
the key is inserted into the keys array at the correct index to keep the keys array
sorted. The value is then inserted into the values array at the same index. The
SortedList<TKey, TValue> class automatically ensures that keys and values
maintain synchronization, even when you add and remove elements. This
means that you can insert key/value pairs into a SortedList<TKey, TValue> in
any sequence; they are always sorted based on the value of the keys.
Comparable to the Dictionary<TKey, TValue> class, a SortedList<TKey,
TValue> collection can’t hold duplicate keys. When you use a foreach
statement to iterate through a SortedList<TKey, TValue>, you receive back a
KeyValuePair<TKey, TValue> item. However, the KeyValuePair<TKey,
TValue> items will be returned sorted by the Key property.
Here is the same example that associates the ages of members of my family
with their names and then prints the information, but this version has been
adjusted to use a SortedList<TKey, TValue> object rather than a
Dictionary<TKey, TValue> collection:

using System;
using System.Collections.Generic;
...
SortedList<string, int> ages = new SortedList<string, int>();
// fill the SortedList
ages.Add("Luis", 47); // using the Add method
ages.Add("Rossanna", 46);
ages["Joelle"] = 20; // using array notation
ages["Jannett"] = 18;
// iterate using a foreach statement
// the iterator generates a KeyValuePair item
Console.WriteLine("The SortedList contains:");
foreach (KeyValuePair<string, int> element in ages)
{
string names = element.Key;
int age = element.Value;
Console.Writeline("Name: {0}, Age: {1}", names, age);
}

The output from this program is sorted alphabetically by the names of my


family members:
The SortedList contains:
Name: Rossanna, Age: 46
Name: Jannett, Age: 18
Name: Joelle, Age: 20
Name: Luis, Age: 47
The HashSet<T> collection class
The HashSet<T> class is optimized for performing set operations such as
determining set membership and generating the union and intersect of sets.
You use the Add method to add items to a HashSet<T>, similarly you use the
Remove method to delete items. However, the real power of the HashSet<T>
class is provided by the IntersectWith, UnionWith, and ExceptWith methods.
These methods modify a HashSet<T> collection to generate a new set that
either intersects with, has a union with, or does not contain the items in a
specified HashSet<T> collection. These operations are destructive inasmuch
as they overwrite the contents of the original HashSet<T> object with the new
set of data. You can also determine whether the data in one HashSet<T>
collection is a superset or subset of another by using the IsSubsetOf,
IsSupersetOf, IsProperSubsetOf, and IsProperSupersetOf methods. These
methods return a Boolean value and are nondestructive.
Internally, a HashSet<T> collection is held as a hash table, enabling fast
lookup of items. However, a large HashSet<T> collection can require a
significant amount of memory to operate quickly.
The subsequent example shows how to populate a HashSet<T> collection and
illustrates the use of the IntersectWith method to find data that overlaps two
sets:
HashSet<string> employees = new HashSet<string>(new string[] { "Fred",
"Bert", "Harry", "Luis" });
HashSet<string> clients = new HashSet<string>(new string[] { "Luis", "Sid",
"Harry", "Rossanna" });employees.Add("Joelle");
clients.Add("Jannett");
Console.WriteLine("Employees:");
foreach (string names in employees)
{
Console.Write(names);
}
Console.WriteLine("\nClients:");
foreach (string names in clients)
{
Console.Write(names);
}
Console.WriteLine("\nClients who are also employees:");
clients.IntersectWith(employees);
foreach (string names in clients)
{
Console.Write(names);
}

This code generates the following output:


Employees: Fred Bert Harry Luis Joelle Clients: Luis Sid Harry Rossanna
Jannett
Clients who are also employees: Luis Harry
Using collection initializers
The examples in the preceding subsections have shown you how to add
individual elements to a collection by using the method most appropriate to
that collection (Add for a List<T> collection, Enqueue for a Queue<T>
collection, Push for a Stack<T> collection, and so on). You can also initialize
some collection types when you declare them, using a syntax similar to that
supported by arrays. For example, the following statement creates and
initializes the sampleNumbers List<int> object shown earlier, demonstrating
an alternate technique to repeatedly calling the Add method:
List<int> sampleNumbers = new List<int>() { 10, 9, 8, 7, 7, 6, 5, 10, 4, 3, 2, 1
};
Internally, the C# compiler actually converts this initialization into a number of
calls to the Add method. Subsequently, you can use this syntax only for
collections that actually support the Add method. (However the Stack<T> &
Queue<T> classes don’t.)
For more complex collections which take key/value pairs, like
Dictionary<TKey, TValue> class, you can stipulate each key/value pair as an
anonymous type in the initializer list, like so:
Dictionary<string, int> ages = new Dictionary<string, int>() { { "Luis", 44 }, {
"Rossanna", 45 }, { "Joelle", 17 }, { "Jannett", 15 } };
Note in a pair, first item is key, second item is value.
The Find methods, predicates, and lambda expressions
Using the dictionary-oriented collections (Dictionary<TKey, TValue>,
SortedDictionary<TKey, TValue>, and SortedList<TKey, TValue>), you can
quickly find a value by specifying the key to search for, and you can use array
notation to access the value, as you have seen in earlier examples. Other
collections that support nonkeyed random access, such as the List<T> and
LinkedList<T> classes, do not support array notation but instead provide the
Find method to locate an item. For these classes, the argument to the Find
method is a predicate that specifies the search criteria to use. The form of a
predicate is a method that examines each item in the collection and returns a
Boolean value indicating whether the item matches. In the case of the Find
method, as soon as the first match is found, the corresponding item is returned.
Note that the List<T> and LinkedList<T> classes also support other methods
such as FindLast, which returns the last matching object, and the List<T> class
additionally provides the FindAll method, which returns a List<T> collection
of all matching objects.
The most convient way to stipulate the predicate is via a lambda expression.
Delegates
A delegate permits you to capture a reference to a method and pass it around
like any other object. In addition it is possible call the captured method as you
would for any other method.
Typically, when you write a statement that invokes a method, you specify the
name of the method (and possibly specify the object or structure to which the
method belongs). It is clear from your code exactly which method you are
running and when you are running it. Look at the following simple example that
calls the cpuCalculate method of a cpuProcessor object (just as an example of
a central processing unit processor):
cpuProcessor p = new cpuProcessor();
p.cpuCalculate();
The next example creates a delegate named cpuCalculateDelegate that
references the cpuCalculate method of the cpuProcessor object. Some
elements of the statement are omitted that declares the delegate because it is
important to understand the concept rather than worry about the syntax
cpuProcessor p = new cpuProcessor();
delegate . . . cpuCalculateDelegate . . .;
cpuCalculateDelegate = p.cpuCalculate;
It is important to understand that the statement that assigns the method reference
to the delegate does not run the method at this point; there are no parentheses
after the method name, and you do not specify any parameters (if the method
takes them). This is just an assignment statement.
Having stored a reference to the cpuCalculate method of the cpuProcessor
object in thedelegate, the application can subsequently invoke the method
through the delegate, like this:
cpuCalculateDelegate();
This looks like an ordinary method call; if you did not know otherwise, it
looks like you might actually be running a method named
cpuCalculateDelegate. However, the Common Language Runtime (CLR)
knows that this is a delegate, so it retrieves the method that the delegate
references and runs that, instead. Later on, you can change the method to which
a delegate refers, so a statement that calls a delegate might actually run a
different method each time it executes. Additionally, a delegate can reference
more than one method at a time (think of it as a collection of method
references), and when you invoke a delegate all of the methods to which it
refers will run.
Declaring a delegate
You must utilise the word delegate, followed by the return type, then the
identifier i.e. the delegate name, succeeded by parameters in brackets () to
declare a delegate. An example:
public delegate int CpuCalculate(int x, int y);
Any method – either static or an instance method- from any accessible class or
struct which matches the delegate type may be allocated to the delegate. You
can then programmatically alter method calls, and in addition plug new code
into standing classes.
Once you declare a delegate type, a delegate object needs to be created with
the new keyword and be associated with a particular method. When creating a
delegate, the argument passed to the new expression is written similar to a
method call, but without the arguments to the method, as listed here:
public delegate void printStringExp(string zy);
...
printStringExp printSg1 = new printStringExp(WriteToVisual);
printStringExp printSg2 = new printStringExp(WriteToPlatter);
The subsequent code exhibits declaration, instantiation, and use of a delegate
which can be utilised to reference methods that take an integer parameter and
returns an integer value.

...
delegate int NumberChanger(int n);
namespace DeclaringADelegateExample
{
class ExampleTestDelegate
{
static int numDelegateEx = 10;
public static int AddNum(int p)
{
numDelegateEx += p;
return numDelegateEx;
}
public static int MultipyNumb(int vee)
{
numberVar *= vee;
return numberVar;
}
public static int getNum()
{
return numberVar;
}
static void Main(string[] args)
{ //create delegate instances
NumChange nc1 = new NumChange(AdditionNumb);
NumChange nc2 = new NumChange(MultipyNumb);
//Call the methods via the delegate objects
nc1(25);
Console.WriteLine("Value of numberVar: {0}", getNum());
nc2(5);
Console.WriteLine("Value of numberVar: {0}", getNum());
}
}
}
The following is outputted to the console:
Value of numberVar: 35
Value of numberVar: 175
Lambda expressions
A lambda expression is an anonymous method utilised to produce delegates
and sometimes expression trees. It permits you to write local functions which
may be passed as arguments or sent back as the value of function calls.
To create a lambda expression, you stipulate input parameters (if any) on the
left side of the lambda operator =>, and you put the expression or statement
block on the opposite side. Taking for example, the lambda expression x => x *
x, it stipulates a parameter that’s named x and returns the value of x squared.
To allot this expression to a delegate type you can utilise the following code:
delegate int del(int i);
static void Main(string[] args)
{
del thisDelegate = x => x * x;
int j = thisDelegate(7); //j = 49
The following produces an expression tree type:
using System.Linq.Expressions;

namespace ExpressionTreeExample
{
class Program
{
static void Main(string[] args)
{
Expression<del> myET = x => x * x;
}
}
}
Lambda expressions forms
Lambda expressions can take series of slightly dissimilar forms. Lambda
expressions were originally part of a mathematical notation called the lambda
calculus, which provides a notation for describing functions. (A function is like
a method) Although the C# language has extended the syntax and semantics of
the lambda calculus in its implementation of lambda expressions, several of
the original rules are still held. Here are some examples illustrating the
different forms of lambda expressions available in C#:
x => x * x // Expression that returns the square of its parameter
// The type of parameter x is inferred from the
context.
x => { return x * x; } // Semantically the same as the preceding
// expression, but using a C# statement block as
// a body rather than a simple expression
(int x) => x / 2 // This expression returns the value of the
// parameter divided by 2
// The type of parameter x is specified explicitly.
() => folder.StopFolding(0) // Calling a method
// The expression takes no parameters.
// The expression might or might not
// return a value.
(x, y) => { x++; return x / y; } // Numerous parameters; the C# compiler
// infers the parameter types.
// The parameter x is passed by value, so
// the effect of the ++ operation is
// local to the expression.
(ref int x, int y) => { x++; return x / y; } // Numerous parameters
// with explicit types
// Parameter x is passed by
// reference, so the effect of
// the ++ operation is permanent.

To summarize, here are some features of lambda expressions of which you


should be aware:
If a lambda expression takes parameters, you specify them in the
parentheses to the left of the => operator. You can omit the types of
parameters, and the C# compiler will infer their types from the context
of the lambda expression. You can send parameters by reference (by
using the ref keyword) if you want the lambda expression to be able to
change its values other than locally, but this is not recommended.
Lambda expressions can return values, but the return type must match
that of the delegate to which they are being added.
The body of a lambda expression can anything from a simple expression
or a series of C# statements, method calls and variable definitions.
Once a method ends variables which were defined in a lambda
expression go out of scope.
Its possible for a lambda expression to access and modify all variables
outside the lambda expression which are in scope when the lambda
expression is defined. Be very careful with this feature!
Events
You have now seen how to declare a delegate type, call a delegate, and create
delegate instances. However, this is only half of the story. Although by using
delegates you can invoke any number of methods indirectly, you still have to
invoke the delegate explicitly. In many cases, it would be useful to have the
delegate run automatically when something significant happens.
The .NET Framework provides events, which you can use to define and trap
significant actions and arrange for a delegate to be called to handle the
situation. Numerous .NET classes expose events. For example, most of the
controls which you can place on a form in a Windows Store app or WPF
application, and the Windows class itself, use events so you can run code when
the user interacts. You can also create your own events.
Declaring an event
You declare an event in a class intended to act as an event source. An event
source is usually a class that monitors its environment and raises an event
when something significant happens. In the automated factory, an event source
could be a class that monitors the temperature of each machine. The
temperature-monitoring class would raise a “machine overheating” event if it
detects that a machine has exceeded its thermal radiation boundary (i.e too
hot). An event keeps a number of methods to call once its raised. Sometimes
these methods are denoted as subscribers. These methods should be ready to
handle the “machine overheating” event and take the essential corrective action
like close down the machines.
You declare an event similarly to how you declare a field. Although, since
events are envisioned to be used with delegates, the type of an event needs to
be a delegate. Also, you need to to prefix the declaration with the event
keyword. The following syntax specifies:
Event, DelegateTypeName, EventName.
Take fore example, HaltMachineryDelegate delegate. It has just been
repositioned to a new class called MonitorTemperature, which offers an
interface to the numerous electronic probes monitoring the temperature of
equipment:

class MonitorTemperature
{
public delegate void HaltMachineryDelegate();
...
}
You can state the MachineTooHot event, which will invoke the
HaltMachineryDelegate, like so:
class MonitorTemperature
{
public delegate void HaltMachineryDelegate();
public event HaltMachineryDelegate MachineTooHot;
...
}
The code logic in the MonitorTemperature class raises the MachineTooHot
event as necessary. Also, you add methods to an event (a process known as
subscribing to the event) rather than adding them to the delegate on which the
event is based. You will look at this aspect of events next.
Subscribing to an event
Like delegates, events come ready-made with a += operator. You subscribe to
an event via a += operative. In this example of an automated factory, the
software controlling every machine can arrange for the shutdown methods to
be called when the MachineTooHot event is raised, like this:

class MonitorTemperature
{
public delegate void HaltMachineryDelegate();
public event HaltMachineryDelegate MachineTooHot;
...
}
...
MonitorTemperature tempMonitor = new MonitorTemperature();
...
tempMonitor.MachineTooHot += (() => { folder.StopFolding(0); });
tempMonitor.MachineTooHot += welder.FinishWelding;
tempMonitor.MachineTooHot += painter.PaintOff;

Notice that the syntax is the same as for adding a method to a delegate. You can
even subscribe by using a lambda expression. When the tempMonitor
MachineTooHot event runs, it will call all the subscribing methods and shut
down the machines.
Unsubscribing from an event
Knowing that you use the += operator to attach a delegate to an event, you can
probably guess that you use the –= operator to detach a delegate from an event.
Calling the –= operator removes the method from the event’s internal delegate
collection. This action is often referred to as unsubscribing from the event.
Raising an event
You can raise an event, just like a delegate, by calling it like a method. Once
you raise an event, every attached delegate is called in sequence. Here for
example is the MonitorTemperature class with a private Notify method that
raises the MachineTooHot event:

class MonitorTemperature
{
public delegate void HaltMachineryDelegate();
public event HaltMachineryDelegate MachineTooHot;
...
private void Notify()
{
if (this.MachineTooHot != null)
{
this.MachineTooHot();
}
}
...
}

This is a frequent expression. You need the null check since an event field is
implicitly null and only becomes non-null when a method subscribes to it by
using the += operator. Should you raise a null event, or try to, you’ll receive a
NullReferenceException exception. You will need to provide the appropriate
arguments when you raise the event should the delegate defining the event
expects parameters.
LINQ
All of your applications written have a very high chance that they need to
connect to an external database at some point. It could be tables in a database,
files on a disk or XML documents online. In order to get data, you are going to
need to query the database and then load the results back into objects. This can
be relatively straightforward but does not take into account any changes in the
structure of the database. If there is a change in a (relational) database, then
you will have a gap between the database and your application.
The .NET Framework offers an straighforward way to deal with the data
called Language-Integrated Query or LINQ. LINQ is a number of technologies
built on query integration into C#. There is LINQ to: SQL, Entities, Objects,
XML and also to Google, Twitter, Ebay.
LINQ prevents your application becoming very tightly coupled with the
structure of the data that its processing. It can be seen as a link between world
of general-purpose programming and the data world. It allows query and set
operations on numerous data sources. Once you understand the LINQ syntax
against an array, you can consider that you will know most of the concepts of
LINQ to database.
Fundamentals
LINQ requires the data to be stored in a data structure that implements the
IEnumerable or IEnumerable<T> interface. It doesn't matter how you store
your data (array, list, any collection type like a queue or stack etc.) as long as
it is enumerable (i.e. you can iterate over the structure).
The basics of LINQ are sequences and elements. A sequence is simple any
object which implements IEnumerable interface. An element is each item in
the sequence. For example:
strings [] names = {“Luis”, “Paul”, “David”};
names - is a sequence and Luis, Paul, and David are elements. This is a local
sequence because it is a local object in memory. A query operator is a method
that transforms a sequence, it usually takes an input sequence and outputs a
transformed output sequence. There around 40 standard query operators.
Simple Query
The following is the simplest LINQ query which takes one input sequence and
one operator. In this example, we apply the Where operator to a simple
array and extract those elements that are four characters or more.
string[] names = {"Luis", "Paul", "David", "Jackie"};

IEnumerable <string> namesFiltered = System.Linq.Enumerable.Where


(names, n => n.Length >= 4);

foreach (string n in namesFiltered)


{
Console.WriteLine(n); // output Luis, Paul, David, Jackie
}

Note: standard query operators are implemented as extension methods, so we


call the Where directly on names as if it was an instant method:
IEnumerable<string> namesFiltered =
names.Where(n => n.Length >= 4);

For this to compile you need to include Using System.Linq;


Projecting data
With Select or SelectMany every element can be transformed in any mode with
a lambda expression. For example, using the example above we can transform
each element into uppercase with the following code change:
IEnumerable<string> namesFiltered =
names.Select(n => n.ToUpper());

The examples following are based on the following arrays:

var clients = new[] {


new { CustID = 1, Forename = "Ossie", Surname = "Oxendine",
BusinessName = "Squaw Valley Hotel" },
new { CustID = 2, Forename = "Yoko ", Surname = "Yousef",
BusinessName = "Copper Distilers" },
new { CustID = 3, Forename = "Roma", Surname = "Rivet",
BusinessName = "Squaw Valley Hotel" },
new { CustID = 4, Forename = "Renate", Surname = "Roark",
BusinessName = "Trey Research" },
new { CustID = 5, Forename = "Valeria", Surname = "Vacca",
BusinessName = "Wingtip Toys" },
new { CustID = 6, Forename = "Janet", Surname = "Jaffee",
BusinessName = "Copper Distillers" },
new { CustID = 7, Forename = "Sofia", Surname = "Seefeldt",
BusinessName = "Wingtip Toys" },
new { CustID = 8, Forename = "Hazel", Surname = "Hinchey",
BusinessName = "Trey Research" },
new { CustID = 9, Forename = "Priscilla", Surname = "Prill",
BusinessName = "Wingtip Toys" },
new { CustID = 10, Forename = "Marlene", Surname = "Most",
BusinessName = "Frames and Windows" }
};
var addresses = new[] {
new { BusinessName = "Squaw Valley Hotel", City = "Frankfurt",
Country = "Germany"},
new { BusinessName = "Copper Distilers", City = "Ottawa",
Country = "Canada"},
new { BusinessName = "Trey Research", City = "Edmonton",
Country = "Canada"},
new { BusinessName = "Wingtip Toys", City = "Paris",
Country = "France"},
new { BusinessName = "Wide World Importers", City = "Lyon",
Country = "France"}
};
Grouping, ordering and aggregating data
LINQ offers the same functionality as SQL in terms of specifying data to be
returned in a specific order. You can have data returned in a particular order.
For example, you can group the rows returned in accordance to one or more
key fields, also you can calculate summary values based on the rows in each
group.
To return data in a specific order, you can use the OrderBy method.
Comparable to the Where and Select methods, OrderBy expects a method as its
argument. This method identifies which expressions you are going to sort the
data on. For instance, you can display the name of each business in the
addresses array in ascending order, like this:
IEnumerable<string> businessNames =
addresses.OrderBy(addr => addr.BusinessName).Select(comp
=>comp.BusinessName);
foreach (string name in businessNames)
{
Console.WriteLine(name);
}

The following is outputted to the console:


Copper Distillers, Squaw Valley Hotel, Trey Research, Wide World Importers,
Wingtip Toys
Should you wish to enumerate the data in descending order, you can instead
utilise the OrderByDescending method. However, if you wish to order by more
than one key value, you can utilise the ThenBy or ThenByDescending method
after OrderBy or OrderByDescending.
var businessGroupedByCountry =
addresses.GroupBy(addrs => addrs.Country);
foreach (var businessPerCountry in businessGroupedByCountry)
{
Console.WriteLine("Country: {0}\t{1} companies",
businessPerCountry.Key, businessPerCountry.Count());
foreach (var business in businessPerCountry)
{
Console.WriteLine("\t{0}", business.BusinessName);
}
}

The output generated by the example code looks like this:


Country: Germany 1 companies
Squaw Valley Hotel
Country: Canada 2 companies
Copper Distillers
Trey Research
Country: France 2 companies
Wingtip Toys
Wide World Importers
Joining data
Join and GroupJoin operators are designed to be efficient with local queries
and support inner and left outer joins. Just like SQL, LINQ gives you the
ability to join multiple sets of data together over on or more common key
fields.
var businessAndClients = clients
.Select(c => new { c.Forename, c.Surname, c.BusinessName })
.Join(addresses, custs => custs.BusinessName, addrs =>
addrs.BusinessName,
(custs, addrs) => new { custs.Forename, custs.Surname, addrs.Country
});
foreach (var row in businessAndClients)
{
Console.WriteLine(row);
}

In order for the code to execute both the clients first name and last name must
be available in the clients array, but the country for each business that clients
work for is stored in the addresses array. The common key between the clients
array and the address array is the business name. The parameters to the Join
method are as follows:
The enumerable collection with which to join
A method that identifies the common key fields from the data identified
by the Select method
A method that identifies the common key fields on which to join the
selected data
A method that specifies the columns you require in the enumerable result
set returned by the Join method
This completes this C# Programming Ebook. I hope this programming guide
has been useful for you. I wish you all the best in your further studies.
References

MSDN C# Programming guide (Guide on key C#


language features):
https://msdn.microsoft.com/en-us/library/67ef8sbd.aspx

Visual Studio Developer Essentials (some great


resources!):
https://www.visualstudio.com/dev-essentials/

Stack overflow (when your program doesn’t work!):


http://stackoverflow.com/

101 LINQ samples (examples you can use in your


programs):
https://code.msdn.microsoft.com/101-LINQ-Samples-3fb9811b

You might also like