0% found this document useful (0 votes)
25 views35 pages

ICT205-Support de Cours 3 Some C# Fundamentals

This document introduces fundamental concepts of C# programming, assuming some prior knowledge of object-oriented languages. It covers creating a simple 'Hello, World!' console application, explains top-level statements, namespaces, using directives, and comments, and discusses data types and string interpolation. The chapter serves as a foundational guide for readers to build upon in subsequent sections of the book.

Uploaded by

andynangmo237
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
25 views35 pages

ICT205-Support de Cours 3 Some C# Fundamentals

This document introduces fundamental concepts of C# programming, assuming some prior knowledge of object-oriented languages. It covers creating a simple 'Hello, World!' console application, explains top-level statements, namespaces, using directives, and comments, and discusses data types and string interpolation. The chapter serves as a foundational guide for readers to build upon in subsequent sections of the book.

Uploaded by

andynangmo237
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 35

Some C# Fundamentals

In this book, we will assume that you have some fundamental knowledge of an object-
oriented programming language such as C#, Java, or C++ . Below we’ll introduce some
concepts that we’ll need throughout this book. We’ll introduce other concepts later in the
book, but this chapter should provide us with some C# knowledge baseline. Feel free to
skip this chapter (or only read selected sections) if you are already proficient in C#.

5.1 Hello World in C# (Console Application)

Let’s create the “Hello, World!” application using a console application in C#. This is the
only console application we’ll create in the entire book. Also, from here on we’ll stop
using Visual Studio Code and we’ll exclusively use Visual Studio.
If you cannot install Visual Studio on your machine (for example, you are using a
Linux distribution), then you should continue to use Visual Studio Code (but this edition
of the book only focuses on Visual Studio).
For this, open the Visual Studio application. There, click on Create a new project
button, then click on the Console App button. Then, in the next window, in the Configure
your new project window, enter a project a name, and select a location, then click on the
Next button.
At the next step, in the Additional Information window, make sure to choose .Net 6.0.
For this demo, make sure to also check the Do not use top-level statements. We’ll explain
this later in this chapter, but for now make sure it is checked and then click Next.
You should get the following code in the Program.cs file (we’ll explain the code
below):

© The Author(s), under exclusive license to Springer Nature Switzerland AG 2024 69


R. A. Mezei, Introduction to the Development of Web Applications Using
ASP .Net (Core) MVC, Synthesis Lectures on Computer Science,
https://doi.org/10.1007/978-3-031-30626-6_5
70 5 Some C# Fundamentals

pcogurceg JgnnqYqtnf
}
kpvgtpcn encuu Rtqitco
}
uvcvke xqkf Ockp*uvtkpi]_"ctiu+
}
Eqpuqng0YtkvgNkpg*$Jgnnq."Yqtnf#$+=
Ä
Ä
Ä

To compile and run this code, you have two options:

• Run without debugging (press Ctrl + F5—or click on the dark green “play” button).

o Faster, but breakpoints will be omitted (we’ll explain breakpoints later in this
chapter).

• Run with debugging (press F5—or click on the light green “play” button)

o May be a little slower, this option is better for debugging (breakpoints will not be
omitted).

Let’s run this application without debugging. It should display “Hello, World!”.

Hello, World!

5.2 Top-Level Statements

If you create another project and follow the same steps as in the previous section, except
that this time, in the Additional Information window, you leave Do not use top-level
statements unchecked, you will get the following code in Program.cs:

11"Ugg"jvvru<11cmc0ou1pgy/eqpuqng/vgorncvg"hqt"oqtg"kphqtocvkqp
Eqpuqng0YtkvgNkpg*$Jgnnq."Yqtnf#$+=

If you run the application, you should get the same result as in the previous section:

Hello, World!
5.3 Namespaces, Using Directive, and Global Using Directive 71

What is happening is as follows. If any one source file (in our case the file named
Program.cs) contains statements outside of a namespace declaration, the compiler will
wrap them inside a Main method, inside a class, and inside a namespace. See more
about this in [1]. Our ASP .Net Core MVC applications that we’ll create in the following
chapters will make use of this.
“Starting in C# 9, you don’t have to explicitly include a Main method in a console
application project. Instead, you can use the top-level statements feature to minimize the
code you have to write. In this case, the compiler generates a class and Main method
entry point for the application” ([2]).
Important note: C# is case sensitive. That is if , IF , and iF are all considered
different. So please be careful.

5.3 Namespaces, Using Directive, and Global Using Directive

5.3.1 Namespaces

The first building blocks for C# applications are namespaces. When we write code, we
organize it into namespaces. Namespaces are containers of code. In them one can cre-
ate other namespaces, classes, enumerations, and so on. To create a namespace, we use
the namespace keyword, we give it a name, and then, within curly braces, we add its
corresponding contents.
For example, to define our first namespace, named FirstNamespace we write.

pcogurceg JgnnqYqtnf
}
000"cff"eqfg"kp"jgtg"000
Ä

Starting with C# version 10, the above code can also be written as follows:

pcogurceg JgnnqYqtnf=

000"cff"eqfg"kp"jgtg"000

To learn more about this, check out [3].

5.3.2 Using Directives

Namespaces can be used as a great way to separate/isolate pieces of code, especially as


a project becomes larger. In the example below, we created two namespaces. The class
72 5 Some C# Fundamentals

created in the second namespace is unknown to the code in the first namespace (you will
get a compiler error if you try to run this code):
pcogurceg JgnnqYqtnf
}
kpvgtpcn encuu Rtqitco
}
uvcvke xqkf Ockp*uvtkpi]_"ctiu+
}
O{Encuu"qdl"?"pgy O{Encuu*+=
Eqpuqng0YtkvgNkpg*$Jgnnq."Yqtnf#$+=
Ä
Ä
Ä

pcogurceg O{UgeqpfPcogurceg
}
encuu O{Encuu
}

Ä
Ä

When you want to use code from different namespaces, you will have two options.
Either use the full class name (that is <namespace name> . <class name>) as below:
pcogurceg JgnnqYqtnf
}
kpvgtpcn encuu Rtqitco
}
uvcvke xqkf Ockp*uvtkpi]_"ctiu+
}
O{UgeqpfPcogurceg0O{Encuu"qdl"?"pgy O{UgeqpfPcogurceg0O{Encuu*+=
Eqpuqng0YtkvgNkpg*$Jgnnq."Yqtnf#$+=
Ä
Ä
Ä

pcogurceg O{UgeqpfPcogurceg
}
encuu O{Encuu
}

Ä
Ä

or use a using directive as shown below:


wukpi O{UgeqpfPcogurceg=
pcogurceg JgnnqYqtnf
}
kpvgtpcn encuu Rtqitco
}
uvcvke xqkf Ockp*uvtkpi]_"ctiu+
}
O{Encuu"qdl"?"pgy O{Encuu*+=
Eqpuqng0YtkvgNkpg*$Jgnnq."Yqtnf#$+=
Ä
Ä
Ä
pcogurceg O{UgeqpfPcogurceg
}
encuu O{Encuu
}

Ä
Ä
5.3 Namespaces, Using Directive, and Global Using Directive 73

There is more to say about namespaces (for example, what happens if you have two
classes with the same name declared in two namespaces and want to use both of them in
a source file?) but since we won’t use them in this book, we skipped them.

5.3.3 Implicit Using Directives

The Console class was created in a namespace called System, which is different than the
current namespace. Yet, for the Console class, we did not need to use (but could have
used) a directive such as

wukpi U{uvgo=

The reason for this is implicit using directives. Based on the type of project you’re
creating, a set of using directives is automatically added to your code by the C# compiler.
In particular, for a Console Application, the compiler already added the following using
directives:

wukpi U{uvgo=
wukpi U{uvgo0KQ=
wukpi U{uvgo0Eqnngevkqpu0Igpgtke=
wukpi U{uvgo0Nkps=
wukpi U{uvgo0Pgv0Jvvr=
wukpi U{uvgo0Vjtgcfkpi=
wukpi U{uvgo0Vjtgcfkpi0Vcumu=

Therefore, we did not need to add them. See more in [4].

5.3.4 Global Using Directives

The using directives only have effect in the file they are declared. If you want a using
directive to import a namespace for your entire application, not only the file in which it
was declared, use a global using directive instead. It is the same as before, but it uses
the keyword global:

inqdcn wukpi O{UgeqpfPcogurceg=

Now, you won’t have to add a using MySecondNamespace; anywhere else in your
project. See more in [4].
74 5 Some C# Fundamentals

5.4 Comments

Comments are pieces of text embedded in our source code that will get ignored by the
compiler. Similarly, to JavaScript, we can have single-line and multi-line comments.

• Single-line comments start with // and continue until the end of that line. Anything
that we include in that line, following //, will be ignored by the compiler.
• Multi-line comments start with /* and continue, possibly on multiple lines, until the
first */. Anything that we include in between /* and */ will be ignored by the compiler.

Example:

You should always document your code by writing meaningful comments.


On your own, you may want to also check out documentation comments in here [5].

5.5 Existing Data Types

For the remainder of this chapter, let’s focus on the example that uses top-level statements,
and build code in it. Here is the starting point (in the Program.cs file):

11"Ugg"jvvru<11cmc0ou1pgy/eqpuqng/vgorncvg"hqt"oqtg"kphqtocvkqp
Eqpuqng0YtkvgNkpg*$Jgnnq."Yqtnf#$+=

In C# all variables must have a declared type. C# is a strongly typed language, so the
compiler will make sure (will enforce that) you only use variables in the context in which
it makes sense for their declared type.
Some C# data types (see more in [6]) we’ll make use of later in this book:

• int—used for whole numbers in the range −2,147,483,648 to 2,147,483,647;


• double—used for fractional numbers;
• bool—used to store Boolean (true/false) values;
• string—used to store strings (sequence of characters);
• DateTime—used to store dates and times.

For example, we let’s create the following variables and assign them some initial values
(delete all other codes from Program.cs and add the following):
5.5 Existing Data Types 75

kpv [gctuQhGzrgtkgpeg"?"34=
fqwdng Ucnct{"?"322222="1,qpg"ecp"cnuq"wug"vjg"Fgekocn"v{rg"jgtg",1
dqqn KuXgvgtcp"?"hcnug=
uvtkpi HwnnPcog"?"$Tc|xcp"C0"Og|gk$=
FcvgVkog"JktkpiFcvg"?"FcvgVkog0Rctug*$2:1371423:":<22<22"CO$+=
FcvgVkog"EwttgpvFcvgVkog"?"FcvgVkog0Pqy= 11fkurnc{u"vjg"ewttgpv"fcvg"cpf"vkog

Then, to display to the console the values of each variable, use the following
Console.WriteLine statements:

Eqpuqng0YtkvgNkpg*[gctuQhGzrgtkgpeg+=
Eqpuqng0YtkvgNkpg*Ucnct{+=
Eqpuqng0YtkvgNkpg*KuXgvgtcp+=
Eqpuqng0YtkvgNkpg*HwnnPcog+=
Eqpuqng0YtkvgNkpg*JktkpiFcvg+=
Eqpuqng0YtkvgNkpg*EwttgpvFcvgVkog+=

If you run the code, you should get something similar to

12

1000000

False

Razvan A. Mezei

8/15/2018 8:00:00 AM

12/10/2022 7:37:30 PM

Because C# is a strongly typed language, once you declare a variable, you can only
assign it values of compatible types. For example, the following results in a compilation
error because string is not a compatible type to be used for integers:

[gctuQhGzrgtkgpeg"?"$vygnxg$=

A related topic here is to use the keyword var when you declare and initialize a
variable, and let the compiler figure out what type to use for the declaration of that
variable. This is called type inference or implicit typing. For example, one can replace.

kpv [gctuQhGzrgtkgpeg"?"34=

with
76 5 Some C# Fundamentals

Since the variable YearsOfExperience is initialized to an integer, the compiler can


deduce that the type of it is an integer, so we can use var instead. This is probably not a
huge win for this example, but as we deal with longer variable names or more complex
types, the var keyword will quickly become convenient.
Important note: The following line of code will result in an error:

xct [gctuQhGzrgtkgpeg=

even if you later add the (separate!) statement.

[gctuQhGzrgtkgpeg"?"34=

This is because in the line var YearsOfExperience; the compiler does not have a value
to use in order to decide what time should be assigned for this variable.

5.6 String Interpolation

We’ll make use of the following several times throughout our book. To build a string that
combines text and variable values, one can use string interpolation. For this, you need
to add the $ right before the string, then inside the string use {} to embed expressions
(for example, variables). Here is an example:

Eqpuqng0YtkvgNkpg*&${gctu"qh"gzrgtkgpeg<"}[gctuQhGzrgtkgpegÄ$+=
Eqpuqng0YtkvgNkpg*&$hwnn"pcog<"}HwnnPcogÄ."ewttgpv"ucnct{<"}Ucnct{Ä$+=
Eqpuqng0YtkvgNkpg*&$jktkpi"fcvg<"}JktkpiFcvgÄ."ewttgpv"fcvg<"}EwttgpvFcvgVkogÄ$+=

This gave us the following:

years of experience: 12

full name: Razvan A. Mezei, current salary: 100000

hiring date: 8/15/208 8:00:00 AM, current date: 12/10/2022 7:43:15 PM

Inside {} one can also use format specifiers. For example, add :c to display the salary
as currency, or :dd/MM/yyyy to specify a date format for the output:

Eqpuqng0YtkvgNkpg*&${gctu"qh"gzrgtkgpeg<"}[gctuQhGzrgtkgpegÄ$+=
Eqpuqng0YtkvgNkpg*&$hwnn"pcog<"}HwnnPcogÄ."ewttgpv"ucnct{<"}Ucnct{<eÄ$+=
Eqpuqng0YtkvgNkpg*&$jktkpi"fcvg<"}JktkpiFcvgÄ."ewttgpv"fcvg<"}EwttgpvFcvgVkog<ff1OO1{{{{Ä$+=
5.7 Enumerations 77

We obtained:

years of experience: 12

full name: Razvan A. Mezei, current salary: $100,000.00

hiring date: 8/15/208 8:00:00 AM, current date: 12/10/2022 7:43:15 PM

5.7 Enumerations

Above we’ve seen some existing data types from C#. But we can also create custom
types. Two ways to create custom types are enumerations and classes. In here we’ll see
enumerations.
To create an enumerated type (enumeration) we use the keyword enum, then use a
name of our choice, and then in {} add the desired values. For example,

gpwo Hcewnv{Ngxgn }KPUVTWEVQT."CUUKUVCPV."CUUQEKCVG."HWNNRTQHGUUQTÄ=

Let’s move this into its own source file. One way to do this is to select this code,
right-click on it, and select the context menu option: Quick Actions and Refactorings ….
Then click on Move type to FacultyLevel.cs and press the enter key:
In the Solution Explorer window, you should see a new file added to your project. If
you double click on that new file (FacultyLevel.cs), you will see that your code has been
moved in there.
Then, we can create variables of this newly created type/enumeration:

Hcewnv{Ngxgn"EwttgpvNgxgn"?"Hcewnv{Ngxgn0CUUKUVCPV=

and use it, just like we used the other variables. For example,

Eqpuqng0YtkvgNkpg*&$Hcewnv{"ngxgn<"}EwttgpvNgxgnÄ$+=
78 5 Some C# Fundamentals

5.8 Classes

Another way to build custom types is by defining/creating classes. This is a very important
topic, and we’ll use it extensively in this book.
Let’s consider the following “type” which currently does not exist in C#. We would
like to work with a type named Instructor. Each instructor should have a name, a hiring
date, and so on (we’ll worry about this in the next section).
If you add the following line of code to your program: Instructor myself; you’ll get a
compilation error, similar to the one below:

CS0246: The type or namespace name ‘Instructor’ could not be found (are you
missing a using directive or an assembly reference?)

One way to create new types was by defining new enumerations (seen in the previous
section). Another way is by defining new classes. To create a new class, we use the class
keyword, followed by a chosen name, and then by {}.
If we add the following code, the above-mentioned error goes away (because now we
have a type named Instructor):

encuu Kpuvtwevqt
}

We can add this code inside Program.cs, but let’s be a little organized. Let’s create a
new file for it, in the same project. In the Solution Explorer window (if it is not already
opened in Visual Studio, then go to View > Solution Explorer to open it), right-click on
the project name and choose Add > Class… Then enter a name for the new class, (please
enter Instructor.cs) and click on the Add button. You should see the newly created file in
the Solution Explorer. It should contain the following lines of code:

namespace HelloWorld2
{
internal class Instructor
{
}
}

Before we continue, make sure to delete the Instructor class definition from Pro-
gram.cs. We do not need to have it defined in two files. Notice that now, the Instructor
type is unknown in our Program.cs file. At the beginning of the Program.cs we need to
5.9 References and Objects 79

add the import directive for the namespace that contains the Instructor class definition.
For the example in the screenshot above, that is,

wukpi JgnnqYqtnf4=

we’ll see more about classes in the next few sections below and use them extensively in
this book.

5.9 References and Objects

Now that we defined a class called Instructor, we can create variables of that type. For
example,

Kpuvtwevqt"o{ugnh=

In this example, the variable myself is what we call a reference (more on it below).
To create a new instance of a class (also called object), we use the new keyword. For
example,

pgy Kpuvtwevqt*+=

The line shown above will create a new instance of type Instructor. In order to be able
to access it, we need some type of handle, a reference, which allows us to access it. In
the example below:

Kpuvtwevqt"o{ugnh"?"pgy Kpuvtwevqt*+=

myself is a reference that points to a newly created object.


Note: Above, we could have used the var keyword as follows:

xct o{ugnh"?"pgy Kpuvtwevqt*+=

Note: Version 10 of C# (and beyond) also allows the code above to be written as.

Kpuvtwevqt"o{ugnh"?"pgy*+=
80 5 Some C# Fundamentals

Fig. 5.1 Shows two


references, myself and
myself2, pointing to the same
one object, created by new
Instructor()

References are a little special. In the sense that they themselves do not hold the object,
they just hold a reference to the object. In particular, in the code below:

Kpuvtwevqt"o{ugnh"?"pgy Kpuvtwevqt*+=
Kpuvtwevqt"o{ugnh4"?"o{ugnh=

only one object is constructed, and we have two references (myself and myself2), both
pointing/referring to the same object (see Fig. 5.1).
Important to remember:

• We use classes to define new types and new blueprints for objects.
• Objects are particular instances of classes.

For example, we can create a new class Car. Then, from it, we can build multiple
instances (also called objects), for example,

Ect"o{Ect"?"pgy Ect*+=
Ect"{qwtEct"?"pgy Ect*+=

Above we created two instances of the Car class (so we have two objects) and we
also have two references (myCar and yourCar) that we can use to reference/access those
objects.

5.10 Instance Variables/Non-static Fields

So far, we created some new classes, but they don’t do much. Let’s add more to them. In
here we’ll add fields. We make use of fields to add characteristics to our classes. Fields
(non-static fields) are also called instance variables.
5.11 Dot Notation 81

Let’s see some examples.


When you think of Instructors, what characteristics do they all have? For example,
each instructor has a name, has a hiring date, and has a level, and some are tenured
while others are not. When we define our Instructor class, we can declare these instance
variables/fields in there. For example,

encuu Kpuvtwevqt
}
11hkgnfu
rwdnke uvtkpi Pcog=
rwdnke FcvgVkog"JktkpiFcvg=
rwdnke Hcewnv{Ngxgn"Hcewnv{Ngxgn= 11eqphwukpiA"ngv)u"fkuewuu vjku
rwdnke dqqn KuVgpwtgf=
Ä

Now that we declared these instance variables in the Instructor class, all instances of
the Instructor class will have a HiringDate, a FacultyLevel, and whether or not they are
tenured (IsTenured).
Note: In the line public FacultyLevel FacultyLevel; the second word is the type of the
instance variable, while the third is the name of the instance variable. The compiler is
able to know which one is which from the context it is used. We’ll talk about the public
access modifier below.
Let’s see one more example. When you think of products that you buy online, what
characteristics do they all have? For example, each product has a name, has a description,
has a price, maybe a manufacturing date, a weight (needed for its shipping), and so on.
Let’s create a new class. This time, let’s use the name Product (yes, the .cs part is optional,
Visual Studio will automatically add this to the newly created file). Here is an example::

encuu Rtqfwev
}
rwdnke uvtkpi RtqfwevPcog=
rwdnke uvtkpi Fguetkrvkqp=
rwdnke fqwdng Rtkeg=
rwdnke FcvgVkog"OcpwhcevwtkpiFcvg=
rwdnke fqwdng Ygkijv=
Ä

Now we can use these classes to build more meaningful objects.

5.11 Dot Notation

To access the various characteristics of an object (to access its fields) we use the so-called
dot notation. Namely, we use a dot after the reference name followed by the name of the
instance variable we would like to access.
82 5 Some C# Fundamentals

Note: We can use the dot notation with other members of a class, not just with fields
(as seen below).
For example,

Kpuvtwevqt"kpuvtwevqt3"?"pgy Kpuvtwevqt*+=11c"pgy"kpuvcpeg"ku"etgcvgf
kpuvtwevqt30Pcog"?"$Tc|xcp"C0"Og|gk$="11tgcf"kv"cu"vjg"Pcog"qh"kpuvtwevqt3"ku"000
kpuvtwevqt30JktkpiFcvg"?"FcvgVkog0Rctug*$2:1371423:":<22<22"CO$+=
kpuvtwevqt30KuVgpwtgf"?"hcnug=
kpuvtwevqt30Hcewnv{Ngxgn"?"Hcewnv{Ngxgn0CUUKUVCPV=

It is important to understand that each instance has its own copy of instance variables.
If we create a second instance, then the Name fields of instance1 and instance2 are not
shared. This is why they are called instance variables.

Kpuvtwevqt"kpuvtwevqt4"?"pgy Kpuvtwevqt*+=11c"pgy"kpuvcpeg"ku"etgcvgf
kpuvtwevqt40Pcog"?"$Uw|cppg"Dctvqp$="11tgcf"kv"cu"vjg"Pcog"qh"kpuvtwevqt4"ku"000
kpuvtwevqt40Hcewnv{Ngxgn"?"Hcewnv{Ngxgn0CUUQEKCVG=

Let’s make use of these instances:

Eqpuqng0YtkvgNkpg*&$Kpuvtwevqt"}kpuvtwevqt30PcogÄ ku"c*p+"}kpuvtwevqt30Hcewnv{NgxgnÄ Rtqhguuqt$+=


Eqpuqng0YtkvgNkpg*&$Kpuvtwevqt"}kpuvtwevqt40PcogÄ ku"c*p+"}kpuvtwevqt40Hcewnv{NgxgnÄ Rtqhguuqt$+=

We obtained (note how each instance (each Instructor in here) has their own instance
fields (their own Name,…)):

Instructor Razvan A. Mezei is a(n) ASSISTANT Professor

Instructor Suzanne Barton is a(n) ASSOCIATE Professor

On your own, create one more object, this time an instance of the Product class created
above. As soon as you type in the. after the instance name, a tool in Visual Studio, called
IntelliSense, will help us choose one of the available fields (and several other options that
will be explained later; hint: inheritance).

5.12 Methods

Above, we’ve seen how we can use non-static fields to store characteristics (or instance
variables). To program behavior and actions that each instance can perform, we can make
use of methods. Think of methods as a named set of statements that we can call when
needed (in particular, we can easily reuse this set of statements).
5.12 Methods 83

Let’s define a couple of methods in our Instructor class. We would like to be able to
change the name of an instructor. To define such a method, we can use code similar to
the one below (we give the entire class, to help you make sure your code is complete):

kpvgtpcn encuu Kpuvtwevqt 11{qw"ecp"tgoqxg"$kpvgtpcn$"kh"{qw"ycpv


}
11hkgnfu
rwdnke uvtkpi Pcog=
rwdnke FcvgVkog"JktkpiFcvg=
rwdnke Hcewnv{Ngxgn"Hcewnv{Ngxgn="11eqphwukpiA"ngv)u"fkuewuu"vjku
rwdnke dqqn KuVgpwtgf=

11ogvjqfu
rwdnke xqkf EjcpigPcog*uvtkpi pgyPcog+
}
Pcog"?"pgyPcog=
Ä

rwdnke kpv [gctuUkpegJktgf*+


}
tgvwtp *kpv+*FcvgVkog0Pqy0Uwdvtcev*JktkpiFcvg+0Fc{u"1"587047+=
Ä
Ä

Above, we defined two (instance) methods. One named ChangeName, and another
named YearsSinceHired. You should note that these methods have access to the instance
variables of the class, so these do not need to be passed as arguments/parameters for the
method.
To make use of these methods, we can again use the dot notation. Since these are meth-
ods, we will not only use their names when we call them, but also must use parentheses,
and if they have required parameters, we need to pass arguments for these parameters.
Let’s add this line in Program.cs.

kpuvtwevqt30EjcpigPcog*$Cngz Og|gk$+=
Eqpuqng0YtkvgNkpg*&$Kpuvtwevqt"}kpuvtwevqt30PcogÄ yqtmgf"jgtg"hqt"
}kpuvtwevqt30[gctuUkpegJktgf*+Ä {gctu$+=

Then compile and run the application. You should get an output similar to

Instructor Razvan A. Mezei is a(n) ASSISTANT Professor

Instructor Suzanne Barton is a(n) ASSOCIATE Professor

Instructor Alex Mezei worked here for 4 years


84 5 Some C# Fundamentals

5.13 The this Keyword

The this keyword inside a class represents the current instance. In particular, the
ChangeName method above could be rewritten as.

rwdnke xqkf EjcpigPcog*uvtkpi pgyPcog+


}
vjku0Pcog"?"pgyPcog=
Ä

In the code shown above, the keyword this is not necessary because from the given
context (a method inside a class) it was clear that Name represents an instance variable
(or a field/property).
The code shown below, however, contains a logical error. Can you spot it?

rwdnke xqkf EjcpigPcog*uvtkpi Pcog+


}
Pcog"?"Pcog=
Ä

Probably the intent is to use the value of the parameter Name (right side of =) to set
the value of the instance variable Name (left side of =). But that’s not what’s happening.
Inside the ChangeName method, the method’s parameter Name will hide the instance field
Name and hence the assignment just sets a value to itself without affecting the instance
variable name. In order to disambiguate which one is which, you can use the this keyword
to specify that the Name from the left side of the assignment operator (=) refers to the
instance variable Name, not the parameter Name:

rwdnke xqkf EjcpigPcog*uvtkpi Pcog+


}
vjku0Pcog"?"Pcog=
Ä

5.14 Access Modifiers

Access modifiers allow us to control what parts of the application have access to our code.
We can apply access modifiers to namespaces, classes, fields, methods, properties, and
others. There are six access modifiers but the most used ones in our book are the following:

• public: the member that has this access modifier can be accessed by any other code.
• private: the member that has this access modifier can only be accessed by code in the
same class (or struct).
5.15 Properties 85

To learn more about them (protected and internal in particular), we recommend the
following [7, 8].

5.15 Properties

Properties are kind of a mix between fields and methods. They are very important,
especially for upcoming chapters.
Let’s first see the need for properties. Let’s look at the following example:

encuu Rtqfwev
}
rwdnke fqwdng Rtkeg=
Ä

What parts of our code have access to the Price field? Since this field is public, any
part of your program (inside or outside of the Product class) has access to it. Any part of
your program can read it, or even modify it.
Challenge: What if you want to allow code outside the Product class to only read the
Price field, but not change it? How can you create such a restriction? How can we provide
such controlled access to our fields?
If you change the access modifier of the Price field to private, then your field is
only accessible inside the Product class, and nowhere else. This only partially solves
the challenge, but not completely.
One solution: One way to solve the above challenge (if you’ve used Java, you’ve
probably seen this) is as follows:

• Make the field private:

rtkxcvg fqwdng Rtkeg=

• Then create public methods that allow us to read the field from the outside of the
Product class (such a method is called a getter or an accessor) and do not create any
public method that allows us to change it:

rwdnke fqwdng igvRtkeg*+


}
tgvwtp Rtkeg=
Ä
86 5 Some C# Fundamentals

This solves our challenge proposed above. Here is how the code put together looks like:

encuu Rtqfwev
}
rtkxcvg fqwdng Rtkeg=

rwdnke fqwdng igvRtkeg*+


}
tgvwtp Rtkeg=
Ä
Ä

From outside on the Product class, we cannot change the price, but we can read it via
the getPrice method (which is publicly accessible). Inside the Main method, code to read
the price of a product would look something like.

Rtqfwev"ncrvqr"?"pgy Rtqfwev*+=
11Eqpuqng0YtkvgNkpg*ncrvqr0Rtkeg+=11GTTQT<"Rtkeg"ku"rtkxcvg
Eqpuqng0YtkvgNkpg*ncrvqr0igvRtkeg*++=""11wug"vjg"igvRtkeg"ogvjqf"kpuvgcf

A similar discussion can be applied to the case where you want to allow users to
modify a field, without being able to read the existing value. We could create a public
method that allows us to change the field (such a method would be called a setter or
mutator). It would look something like.

rwdnke xqkf ugvRtkeg*fqwdng pgyRtkeg+


}
Rtkeg"?"pgyRtkeg=
Ä

Another/A better solution: C# has a more elegant way to solve this challenge (and
many related ones), by making use of Properties. Here, we’ll only give a simplified
description of properties since we won’t use their full potential, but we do encourage
you to read more information on properties here [9]. We will replace the Price field
declaration and the definition of the accessor with the following one line (that completely
solves the above given challenge):

rwdnke fqwdng Rtkeg"}"igv="rtkxcvg ugv="Ä

Let’s test our code in Main. Notice how we use the dot notation on the property:

Rtqfwev"ncrvqr"?"pgy Rtqfwev*+=
11ncrvqr0Rtkeg"?"32;;0;;="=11GTTQT<"Rtkeg"ugvvgt"ku"rtkxcvg
Eqpuqng0YtkvgNkpg*ncrvqr0Rtkeg+=""11dwv"vjg"igvvgt"ku"rwdnke
5.16 Constructors 87

From the code given above, we can see that we are able to read the value of Price, but
not change it in Main.
If you want to allow Main to only change the value of Price but not read it, you will
use the following property declaration instead:

rwdnke fqwdng Rtkeg"}"rtkxcvg igv="ugv="Ä

Read the source mentioned above ([9]) to also learn about computed properties, vali-
dation, and many other capabilities that properties have. We will make extensive use of
properties, but we will probably just use them in the following form:

rwdnke fqwdng Rtkeg"}"igv="ugv="Ä

5.16 Constructors

Constructors are special methods that are used when creating new objects/instances.
They look like regular methods but their name must match the name of the class in which
they are defined, and they do not have a return type. If (and only if!) you define a class
and do not include a constructor definition, one will automatically be created and added
for you by the compiler. We typically use constructors to set the initial state/values for
an object.
Constructors that have no parameters are called default constructors. In the line below,
when we create a new object of type Product, we are calling the default constructor
defined in the Product class:

Rtqfwev"ncrvqr"?"pgy Rtqfwev*+=

Since we did not define an explicit default constructor, one was added for us
automatically. Check out the output of

Eqpuqng0YtkvgNkpg*ncrvqr0Rtkeg+="11kv"fkurnc{u"2"*fghcwnv"xcnwg"hqt"fqwdng+

Now, let’s explicitly define a default constructor in the Product class:

rwdnke Rtqfwev*+
}
Rtkeg"?"320;;=
OcpwhcevwtkpiFcvg"?"FcvgVkog0Pqy=
Ä
88 5 Some C# Fundamentals

Run again your code and see how the output changes, because we start with a different
initial value for Price:

Eqpuqng0YtkvgNkpg*ncrvqr0Rtkeg+="11kv"pqy"fkurnc{u"320;;"*fghcwnv"eqpuvtwevqt"ugv"vjku"xcnwg+

5.17 Method Overloading

We can have multiple methods with the same name (as long as their parameters have
different types or a different number of parameters)—this is called method overloading.
Similarly, we can have multiple constructors. Constructors that have parameters are called
non-default constructors.
Let’s see an example—add a second constructor to the Product class.

rwdnke Rtqfwev*fqwdng kpkvkcnRtkeg+


}
Rtkeg"?"kpkvkcnRtkeg=
Ä

Now, in Main, let’s test these constructors:

Rtqfwev"fgumvqr"?"pgy Rtqfwev*:;;089+=11kv"ecnnu"vjg"pqp/fghcwnv"eqpuvtwevqt"
Eqpuqng0YtkvgNkpg*fgumvqr0Rtkeg+="11kv"fkurnc{u":;;089

Rtqfwev"ncrvqr"?"pgy Rtqfwev*+=11kv"ecnnu"vjg"fghcwnv"eqpuvtwevqt"
Eqpuqng0YtkvgNkpg*ncrvqr0Rtkeg+="11kv"fkurnc{u"320;;

5.18 Conditionals, Loops, and Lists

We will assume that you understand and can work with if statements and various forms
of loops (for, while, foreach). Below we will give a few brief examples but if you need
more resources, we recommend the following [10, 11].
Let’s write an example where we create a list of Instructors. Then, we check if the list
is empty. If it is empty, we display “There are no instructors in the list!”. Otherwise, we
display the name of each instructor.
At the end of the Program.cs file add the following code:
5.18 Conditionals, Loops, and Lists 89

11ngv)u"etgcvg"c"nkuv"qh"kpuvtwevqtu
Nkuv>Kpuvtwevqt@"EUFgrctvogpv?"pgy Nkuv>Kpuvtwevqt@*+=
EUFgrctvogpv0Cff*pgy Kpuvtwevqt"}"Pcog"?"$Fcokcp"Tqnhuqp$."Hcewnv{Ngxgn"?"
Hcewnv{Ngxgn0CUUKUVCPV."KuVgpwtgf"?"hcnug Ä+=
EUFgrctvogpv0Cff*pgy Kpuvtwevqt"}"Pcog"?"$Guvgnn"Iqvvnkgd$."Hcewnv{Ngxgn"?"
Hcewnv{Ngxgn0CUUQEKCVG."KuVgpwtgf"?"vtwg Ä+=
EUFgrctvogpv0Cff*pgy Kpuvtwevqt"}"Pcog"?"$Nkppgc"Mqgnrkp$."Hcewnv{Ngxgn"?
Hcewnv{Ngxgn0HWNNRTQHGUUQT."KuVgpwtgf"?"vtwg Ä+=
EUFgrctvogpv0Cff*pgy Kpuvtwevqt"}"Pcog"?"$Pcppkg"Nkvvng$."Hcewnv{Ngxgn"?"
Hcewnv{Ngxgn0HWNNRTQHGUUQT."KuVgpwtgf"?"hcnug Ä+=
kh*EUFgrctvogpv0Eqwpv"??"2+"11ejgem"kh"vjg"nkuv"ku"gorv{
}"""11hqt"cp"gorv{"nkuv fkurnc{"c"oguucigu
Eqpuqng0YtkvgNkpg*$Vjgtg"ctg"pq"kpuvtwevqtu"kp"vjg"nkuv#$+=
Ä
gnug
}"""11hqt"c"pqp/gorv{"nkuv fkurnc{"vjg"pcog"qh"gcej"kpuvtwevqt
hqt*kpv k?2="k>"EUFgrctvogpv0Eqwpv="k--+
}
Eqpuqng0YtkvgNkpg*EUFgrctvogpv]k_0Pcog+=
Ä
Ä

Note: In class we typically ask students to help us provide some sample data. This is
more fun this way and it provides another opportunity for students’ engagement.
Running this code, we get the following displayed:

Damian Rolfson

Estell Gottlieb

Linnea Koelpin

Nannie Little

Let’s now rewrite the above code so we make use of the var keyword and use foreach
instead of the for loop. We’ll get the same output.

11ngv)u"etgcvg"c"nkuv"qh"kpuvtwevqtu
xct EUFgrctvogpv?"pgy Nkuv>Kpuvtwevqt@*+=
EUFgrctvogpv0Cff*pgy Kpuvtwevqt"}"Pcog"?"$Fcokcp"Tqnhuqp$."Hcewnv{Ngxgn"?"
Hcewnv{Ngxgn0CUUKUVCPV."KuVgpwtgf"?"hcnug Ä+=
EUFgrctvogpv0Cff*pgy Kpuvtwevqt"}"Pcog"?"$Guvgnn"Iqvvnkgd$."Hcewnv{Ngxgn"?"
Hcewnv{Ngxgn0CUUQEKCVG."KuVgpwtgf"?"vtwg Ä+=
EUFgrctvogpv0Cff*pgy Kpuvtwevqt"}"Pcog"?"$Nkppgc"Mqgnrkp$."Hcewnv{Ngxgn"?"
Hcewnv{Ngxgn0HWNNRTQHGUUQT."KuVgpwtgf"?"vtwg Ä+=
EUFgrctvogpv0Cff*pgy Kpuvtwevqt"}"Pcog"?"$Pcppkg"Nkvvng$."Hcewnv{Ngxgn"?"
Hcewnv{Ngxgn0HWNNRTQHGUUQT."KuVgpwtgf"?"hcnug Ä+=

kh*EUFgrctvogpv0Eqwpv"??"2+"11ejgem"kh"vjg"nkuv"ku"gorv{
}"""11hqt"cp"gorv{"nkuv fkurnc{"c"oguucig
Eqpuqng0YtkvgNkpg*$Vjgtg"ctg"pq"kpuvtwevqtu"kp"vjg"nkuv#$+=
Ä
gnug
}"""11hqt"c"pqp/gorv{"nkuv fkurnc{"vjg"pcog"qh"gcej"kpuvtwevqt
hqtgcej*xct"kpuvtwevqt"kp EUFgrctvogpv+
}
Eqpuqng0YtkvgNkpg*kpuvtwevqt0Pcog+=
Ä
Ä
90 5 Some C# Fundamentals

5.19 Collections and Generic Collections

This section is not meant to teach you generic programming. Instead, we want to make
you aware of it. Generic programming, in particular generic collections, are used quite a
bit in .Net applications. We will also make use of them in our book.
Collections are classes that allow you to group and manage multiple related objects.
Some examples of collections are array lists, linked lists, stacks, queues, and so on.
There are collection classes developed in the System.Collections namespace that store
everything as instances of class Object. Example of classes defined in here: ArrayList,
(there are no linked lists!), Stack, Queue, and others (see more in [12]). You should not use
them in new development, and consider them obsolete. Better choices are the following.
There are collection classes developed in the System.Collections.Generic namespace—
these are generic classes, and users of these classes get to specify what types of objects
they want to store in these collections. Examples of classes defined in here: List<T>,
LinkedList<T>, Stack<T>, Queue<T>, and others (see more in [13]).
In the previous section, we made use of such generic class List.

11ngv)u"etgcvg"c"nkuv"qh"kpuvtwevqtu
Nkuv>Kpuvtwevqt@"EUFgrctvogpv?"pgy Nkuv>Kpuvtwevqt@*+=

The class name is List, and in < > we specify the type of elements we want to store
in our collection/list. In the example above, we used Instructor.
Let’s see another example. If we want to create a generic array list of whole numbers,
we can use code similar to the following:

Nkuv>kpv@"itcfgu"?"pgy Nkuv>kpv@*+="11etgcvg"c"nkuv"qh"kpvgigtu

To add elements to this list, we can use the Add method:

itcfgu0Cff*322+=
itcfgu0Cff*;2+=
itcfgu0Cff*;:+=
itcfgu0Cff*87+=

5.20 Inheritance

Inheritance is a very important topic; we’ll make use of it throughout this book. We’ll
only cover here what we need to know for this book, but please consider learning more
about it on your own. Here is a resource we recommend [14]:
5.20 Inheritance 91

Inheritance is the process of creating new classes by extending existing ones. The
new class is called a child class or derived class and the existing/original class is called
the parent class or base class. Below we give a quick example. For simplicity (and
demonstration purposes), we’ll overuse the public access modifier, but in a real context,
you should question if that is the right access modifier to use.
For our example, let’s create a very simple class called User. For it, let’s create a new
file, called User.cs and put the code in this file. What characteristics does each User have?
What can each User do? The User class will be our base class.
A simple implementation for this class would be the following:

Supposes now that your application needs to create more specialized Users. For
example, assume that we need

• Professors (these are Users, in the sense they need to be able to login/logout, but also
have characteristics such as whether or not they are tenured, maybe a hiring date) and
• Students (these are also Users, they too need to be able to login/logout, but also have
characteristics such as major and admission date).

How do we create these Professor and Student classes?


Let’s create a new file and in it a class named Professor. Since a Professor is a User, we
will make use of inheritance. Note the use of : to specify inheritance. Here is a simplified
example::
92 5 Some C# Fundamentals

Note: All fields, properties, and methods from the base class will be inherited in the
derived class. Whether or not the derived class has access to all of them depends on the
access modifiers being used. In particular, a Professor has a UserName, a Password, and
can Login and Logout:

Rtqhguuqt"rtqh"?"pgy Rtqhguuqt*+=
rtqh0WugtPcog"?"$tog|gk$=
rtqh0Rcuuyqtf"?"$Rcuuyqtf345#$=
rtqh0Nqikp*+=
rtqh0Nqiqwv*+=
rtqh0KuVgpwtgf?"vtwg=

As you type prof. see what options IntelliSense shows you.


Note: In the screenshot above, you may notice some methods that we did not include
in our code above. In particular, note the methods GetHashCode, GetType, and ToString.
They are the result of inheritance too. When you create a new class, if you do not specify
any base class for it, the C# compiler will automatically make your new class a derived
class of the Object class. Because of it, methods defined in the Object class will get
inherited by your new class. In the example above, the methods GetHashCode, GetType,
and ToString are inherited by the User class. Since Professor inherits from User class,
Professor will inherit all properties, fields, and methods from User, including the methods
GetHashCode, GetType, and ToString.
Next, we can once again use inheritance to create a Student class that has a UserName,
a Password and can Login:

encuu Uvwfgpv <"Wugt


}
rwdnke uvtkpi Oclqt"}"igv="ugv="Ä
rwdnke FcvgVkog"CffokuukqpFcvg"}"igv="ugv="Ä
Ä

Then, in the Program.cs file we could use code such as the one below:

Uvwfgpv"uv"?"pgy Uvwfgpv*+=""""""11etgcvgu"c"pgy"kpuvcpeg"qh"Uvwfgpv
uv0WugtPcog"?"$tc|xcp0og|gk$=""""11rtqrgtv{"kpjgtkvgf"htqo"Wugt
uv0Rcuuyqtf?"$Rcuuyqtf346#$="""""11rtqrgtv{"kpjgtkvgf"htqo"Wugt
uv0CffokuukqpFcvg"?"FcvgVkog0Pqy=11rtqrgtv{"fghkpgf"kp"vjg"Uvwfgpv"encuu
uv0Nqikp*+=
uv0Nqiqwv*+=

5.21 The base Keyword and the Constructors

Something important happens with the constructors. To see this, let’s add default
constructors in both the User class and in the Professor class:
5.21 The base Keyword and the Constructors 93

rwdnke Rtqhguuqt*+11fghcwnv"eqpuvtwevqt
}
Eqpuqng0YtkvgNkpg*$Jgnnq"htqo"vjg"Rtqhguuqt"fghcwnv"eqpuvtwevqt$+=
Ä

And

rwdnke Wugt*+11fghcwnv"eqpuvtwevqt
}
Eqpuqng0YtkvgNkpg*$Jgnnq"htqo"vjg"Wugt"fghcwnv"eqpuvtwevqt$+=
Ä

To double-check your code, your Professor class should now look similar to (Fig. 5.2).
Then, in Program.cs, remove all codes (except for the using directive) and add the
following:

Rtqhguuqt"rtqh"?"pgy Rtqhguuqt*+=

Then, run your program. The output should be similar to

Hello from the User default constructor

Hello from the Professor default constructor

What you should see is that the constructor for our Professor class, automatically
called the constructor for the User class (which is the base class for our Professor).

Fig. 5.2 Shows the Professor class that extends the User class. It contains two properties, IsTenured
and HiringDate, and a default constructor
94 5 Some C# Fundamentals

IMPORTANT: In general, when we create instances of derived classes, the constructors


for our derived class will always call the default constructor for the base class before it
runs the code in the constructor (of our derived class).
Now, let’s add non-default constructors to each class and see what happens in this case.
Add the following non-default constructors into their respective classes:

rwdnke Wugt*kpv pwo+"11pqp/fghcwnv"eqpuvtwevqt


}
Eqpuqng0YtkvgNkpg*$Jgnnq"htqo"vjg"Wugt"pqp/fghcwnv"eqpuvtwevqt$+=
Ä

and

rwdnke Rtqhguuqt*kpv pwo+"11pqp/fghcwnv"eqpuvtwevqt


}
Eqpuqng0YtkvgNkpg*$Jgnnq"htqo"vjg"Rtqhguuqt"pqp/fghcwnv"eqpuvtwevqt$+=
Ä

Now, change the line in Program.cs so it looks similar to the line below (essentially
calling the non-default constructor from the Professor class):

Rtqhguuqt"rtqh"?"pgy Rtqhguuqt*4245+=

Run the code and check out the results. You should obtain the following:

Hello from the User default constructor

Hello from the Professor non-default constructor

You should notice that the non-default constructor from the Professor class was called.
This should not be a surprise since we passed a value to the constructor when we cre-
ated the new instance of Professor class. But the important part to observe is that this
constructor in turn called the default constructor from the base class (User class in here).
That means, all constructors, by default, will call the base constructor from the base
class. We can change that behavior by explicitly calling the base constructor of our choice
(default or non-default). This is where we’ll make use of the base keyword.
Currently our non-default Professor constructor looks like

rwdnke Rtqhguuqt*kpv pwo+"11pqp/fghcwnv"eqpuvtwevqt


}
Eqpuqng0YtkvgNkpg*$Jgnnq"htqo"vjg"Rtqhguuqt"pqp/fghcwnv"eqpuvtwevqt$+=
Ä
5.22 Interfaces 95

This is equivalent to

rwdnke Rtqhguuqt*kpv pwo+ <"dcug*+ 11pqp/fghcwnv"eqpuvtwevqt


}
Eqpuqng0YtkvgNkpg*$Jgnnq"htqo"vjg"Rtqhguuqt"pqp/fghcwnv"eqpuvtwevqt$+=
Ä

which is why the constructor calls the default constructor from the base class.
If we want to call the non-default constructor from the base class, we can pass
parameters to the base() call, as follows:

rwdnke Rtqhguuqt*kpv pwo+ <"dcug*pwo,pwo+ 11pqp/fghcwnv"eqpuvtwevqt


}
Eqpuqng0YtkvgNkpg*$Jgnnq"htqo"vjg"Rtqhguuqt"pqp/fghcwnv"eqpuvtwevqt$+=
Ä

Now, if we run again the program, we’ll see that our non-default constructor from
Professor class called the non-default constructor from its base class (the User class).

Hello from the User non-default constructor

Hello from the Professor non-default constructor

To recap, all constructors (default or non-default) from a class, by default, call the
base class’s default constructor. If we want a constructor to call a non-default constructor
from the base class, we add the call to base() and pass parameters needed for that base
non-default class constructor.
Methods do not have the same cascading effect as constructors, but we can build one
using the base keyword again. We’ll skip this part since we won’t use it in our book.

5.22 Interfaces

Although we’ll make extensive use of interfaces, in this book we will only define very
few interfaces. As such we’ll only briefly introduce them in here.
IMPORTANT: As a convention, interface names always start with a capital I (see
examples below).
96 5 Some C# Fundamentals

5.22.1 Some Motivation

Let’s start with an example of interface that is included in the System library, namely
IComparable.
If we want to sort integers, we can do so as long as we know how to compare each
pair of numbers. Similarly, if we want to compare instances of let’s say Professor class,
again we can do so, as long as we have a way to compare every two professors. The
essence of what we are trying to suggest here is that sometimes we want to expect similar
functionalities from unrelated classes. If they are not related, inheritance is probably not
the way to go (you should not use inheritance for unrelated classes). In this case, the
interfaces will be the appropriate choice.
In particular, the generic class List, which can store elements of any given type, can
also sort them, as long as the type used in the List implements the IComparable interface.

5.22.2 How to Define an Interface

To define an interface, we use the keyword interface, we choose a name (which by


convention should start with I), and then, inside a block (use {}), we include zero or
more declarations for methods, properties, (and starting with C# 8.0) fields, and other
members.
Here is an example. In the Solution Explorer window, right-click on the project’s name,
select Add > New Item …, then click on the option Interface and enter a name, say
IPrintable, then click on the Add button.
We can now define our interface. We’ll define a simple one that contains only one
method declaration:

kpvgthceg KRtkpvcdng
}
xqkf RtkpvVqEqpuqng*+=
Ä

Important to notice: We did not include an access modifier (this is explained below).

5.22.3 How to Implement an Interface

Next, let us implement this interface. For a class to implement an interface, we need to.

• declare this by using the : (just like inheritance, which is why it’s important to use the
I in the interface name!);
• implement each member from the interface in our class.
5.23 How to Use an Interface 97

Let’s see this by example. Let’s modify the Professor class so it now implements the
IPrintable interface.
Since we already have an inheritance declaration (: is already in there) we only need
to add a comma after User and add the name of the interface we intend to implement:

encuu Rtqhguuqt <"Wugt."KRtkpvcdng


}
11000
Ä

Then, to implement the specified interface(s), we need to define all members from the
interface declaration. In particular, we’ll need to define a void PrintToConsole(); method.
Important to note: All members from the interface must be added as public members
in the class (regardless of whether or not the interface uses the public access modifier
when it declares those members). So, we’ll need to define a public void PrintToConsole();
method.
What you put in this method it’s up to you, the interface just cares that you have a
definition for each member of the interface. Let’s add the following method definition in
the Professor class:

rwdnke xqkf RtkpvVqEqpuqng*+


}
Eqpuqng0YtkvgNkpg*&$Wugt<"}WugtPcogÄ."Jktkpi"fcvg<"}JktkpiFcvgÄ$+=
Ä

Note: One class can only inherit from one base class, but it can implement multiple
interfaces.
Important note: One can have multiple completely unrelated classes, all implementing
the same interface. How can this be useful? That’s what we’ll see below.

5.23 How to Use an Interface

Let’s start with the following example. If we define the method below:

xqkf Jcrr{Ogvjqf*Wugt"wut+
}
11vq"fq000
Ä

what can type of parameters can you pass to this method? The answer is you can pass in
any instance of the User class, or any class derived from User (in particular, you can pass
in an instance of a Professor).
98 5 Some C# Fundamentals

Can you pass in an integer? Can you run HappyMethod(2024)? The answer is no,
because 2024 is not an instance of User (or any derived class from User).
Interfaces provide us with more flexibility. Let’s create a method, which uses an inter-
face as a parameter type. For example, add the following to the end of the Program.cs
file:

xqkf Jcrr{Ogvjqf*KRtkpvcdng"qdl+
}
qdl0RtkpvVqEqpuqng*+=
Ä

What can you pass to such a method? The answer is an instance of any class (or derived
class) that implements the IPrintable interface. In particular, if you have two unrelated
classes, say Professor and Classroom, both implementing the IPrintable interface, then
you could pass an instance of either one to the HappyMethod. That’s quite some flexibility.
See more about interfaces in here [15].

5.24 Lambda Expressions

This is a very brief introduction to lambda expressions. They are very convenient when
we want to pass certain information to methods. See more in [16].
Lambda expressions are nice short ways to create so-called anonymous functions.
Lambda expressions make use of the lambda operator =>(read it as: “goes to” or
“becomes”) and have two forms:

• expression lambda: (list of params) => expression

o example: (a, b) => a + b;

• statement lambda: (list of params) => { list of statements}

o example: (a, b) => {int c = a + b; return c;};


o example: (a, b) => {return a+b;};

If we have exactly one parameter, then the parentheses around it are not required. The
following examples are equivalent:

• example: (a) => a * a ;


• example: a => a * a ;
5.24 Lambda Expressions 99

Let’s see some practical examples. Earlier, we created the following list:

xct EUFgrctvogpv"?"pgy Nkuv>Kpuvtwevqt@*+=


EUFgrctvogpv0Cff*pgy Kpuvtwevqt"}"Pcog"?"$Fcokcp"Tqnhuqp$."Hcewnv{Ngxgn"?"Hcewnv{Ngxgn0CUUKUVCPV."KuVgpwtgf"?"hcnug Ä+=
EUFgrctvogpv0Cff*pgy Kpuvtwevqt"}"Pcog"?"$Guvgnn"Iqvvnkgd$."Hcewnv{Ngxgn"?"Hcewnv{Ngxgn0CUUQEKCVG."KuVgpwtgf"?"vtwg Ä+=
EUFgrctvogpv0Cff*pgy Kpuvtwevqt"}"Pcog"?"$Nkppgc"Mqgnrkp$."Hcewnv{Ngxgn"?"Hcewnv{Ngxgn0HWNNRTQHGUUQT."KuVgpwtgf"?"vtwg Ä+=
EUFgrctvogpv0Cff*pgy Kpuvtwevqt"}"Pcog"?"$Pcppkg"Nkvvng$."Hcewnv{Ngxgn"?"Hcewnv{Ngxgn0HWNNRTQHGUUQT."KuVgpwtgf"?"hcnug Ä+=

To display this list, we can use the following code:

hqtgcej*xct"kpuvt"kp EUFgrctvogpv+
}
Eqpuqng0YtkvgNkpg*&$Pcog<"}kpuvt0PcogÄ."Ngxgn<"}kpuvt0Hcewnv{NgxgnÄ."Vgpwtgf<"}kpuvt0KuVgpwtgfÄ $+=
Ä

And obtain

Name: Damian Rolfson, Level: ASSISTANT, Tenured: False

Name: Estell Gottlieb, Level: ASSOCIATE, Tenured: True

Name: Linnea Koelpin, Level: FULLPROFESSOR, Tenured: True

Name: Nannie Little, Level: FULLPROFESSOR, Tenured: False

which is the order in which we added each instructor into our list.
What if we would like to sort this list? Before the foreach statement add the following
statement:

EUFgrctvogpv0Uqtv*+=

Run again your code. Did it work? The output should contain a rather error message,
including.

Unhandled exception. System.InvalidOperationException: Failed to compare two


elements in the array.

What this means is that the Sort method did not know how to compare two instances
of Instructor.
We now have some solutions. One is to implement the IComparable interface inside
the Instructor class.
Another, which we’ll see below, is to provide a lambda expression to the Sort method,
an expression that is essentially a comparison method that can be used by Sort when
sorting our list.
100 5 Some C# Fundamentals

Let’s sort by name. Replace the CSDepartment.Sort(); with.

EUFgrctvogpv0Uqtv**kpuvt3."kpuvt4+"?@"Uvtkpi0Eqorctg*kpuvt30Pcog."kpuvt40Pcog+"+=

Above note that we provided the Sort method a lambda expression, an anonymous
method that can be used to compare every two instructors. Running the code above, you
should now get the list sorted by Name:

Name: Damian Rolfson, Level: ASSISTANT, Tenured: False

Name: Estell Gottlieb, Level: ASSOCIATE, Tenured: True

Name: Linnea Koelpin, Level: FULLPROFESSOR, Tenured: True

Name: Nannie Little, Level: FULLPROFESSOR, Tenured: False

Similarly, we can sort by Tenure. In this example, we will use the CompareTo method
that is included for Boolean values. Replace the statement above with.

EUFgrctvogpv0Uqtv**kpuvt3."kpuvt4+"?@"kpuvt30KuVgpwtgf0EqorctgVq*kpuvt40KuVgpwtgf+"+=

Running the code again, we now get.

Name: Damian Rolfson, Level: ASSISTANT, Tenured: False

Name: Nannie Little, Level: FULLPROFESSOR, Tenured: False

Name: Estell Gottlieb, Level: ASSOCIATE, Tenured: True

Name: Linnea Koelpin, Level: FULLPROFESSOR, Tenured: True

See how flexible the Sort method was? Allowing us to use lambda expressions, we
were able to quickly specify how to sort our list. Above we’ve seen how to sort the list
by name, or by tenure.

5.25 LINQ

This is another very brief introduction. To read more about LINQ, we recommend the
following [17].
5.25 LINQ 101

LINQ stands for Language-Integrated Query and it provides “integration of query


capabilities directly into the C# language”. LINQ works very nicely with lambda
expressions.
Here is one example. On a List instance, we can use Where for filtering. Replace the
foreach statement above with:

hqtgcej*xct"kpuvt"kp EUFgrctvogpv0Yjgtg*kpuv"?@"kpuv0Pcog0Eqpvckpu*$pp$+++
}
Eqpuqng0YtkvgNkpg*&$Pcog<"}kpuvt0PcogÄ."Ngxgn<"}kpuvt0Hcewnv{NgxgnÄ."Vgpwtgf<"}kpuvt0KuVgpwtgfÄ $+=
Ä

We were able to narrow down the list to only elements that match a specific condition
(given as a lambda expression):

Name: Nannie Little, Level: FULLPROFESSOR, Tenured: False

Name: Linnea Koelpin, Level: FULLPROFESSOR, Tenured: True

We can then use another operation on the results of Where. One could, for example,
use another Where.

And obtain:

Name: Nannie Little, Level: FULLPROFESSOR, Tenured: False

One last example:

will yield:

Name: Linnea Koelpin, Level: FULLPROFESSOR, Tenured: True

Name: Nannie Little, Level: FULLPROFESSOR, Tenured: False


102 5 Some C# Fundamentals

5.26 Working with null Values

We mentioned earlier that C# is a strongly typed language. That means that if a variable
is, let’s say, declared as an int, then you can only assign compatible values to it.
In particular, if you declare number as an int, then you cannot assign a string value or
even a null value. You would get a compiling error:

kpv pwodgt=
pwodgt"?"32="11QM
pwodgt"?"$vyq$="11gttqt"/ ytqpi"v{rg
pwodgt"?"pwnn="11gttqt"/ ytqpi"v{rg

When dealing with web applications, it is possible the user may fill out all form fields.
How would you treat that?
One is to use nullable types. “A nullable value type T? represents all values of its
underlying value type T and an additional null value” (see more in [18]).
If you put a ? next to the int type, you obtain int? which is a nullable type, namely it
represents all integers and the null value. In the previous example, we now get

kpvA"pwodgt=
pwodgt"?"32="11QM
pwodgt"?"$vyq$="11gttqt"/ uvknn"ytqpi"v{rg
pwodgt"?"pwnn="11QM"pqy

Another example: bool represents the values true and false. Therefore, bool? represents
the values: true, false, null.
Important: When you work with nullable types you should check for null values.
There is a lot more to learn about this topic, but we’ll skip the rest. We recommend
you to also check out the following [19]. Also, we won’t use the following but we want
to challenge you to find out what is the difference between each of the following:

kpv]_"xcnwgu=

kpvA]_"xcnwgu=

kpv]_A xcnwgu=

kpvA]_A xcnwgu=

5.27 Solution Files .sln

To reopen a Visual Studio project (in particular an ASP .Net Core MVC project), you
should locate and double click on the .sln file. This is typically in the same directory as
the project, or one level up.
5.28 Other Resources for Learning C# 103

We have seen (many times) learners trying to open a project by opening the .cs (the
C#) file, which may (typically) also open in Visual Studio. But once the file opens, there
is no compile button. Instead you should open the .sln file (a text-based file). See more
about this file here [20].

5.28 Other Resources for Learning C#

This chapter is not meant to provide a comprehensive C# tutorial. For that, we recommend
the following:

• W3School’s C# tutorial: see [10].


• The Microsoft’s C# documentation: see [11] (our main C# source).

You might also like