C#
C#
C#
The .NET Framework consists of the Common Language Runtime (CLR) and the .NET
Framework class library.
The CLR is the foundation of the .NET Framework. It manages code at execution time,
providing core services such as memory management, code accuracy, and many other
aspects of your code.
The class library is a collection of classes, interfaces, and value types that enable you to
accomplish a range of common programming tasks, such as data collection, file access, and
working with text.
C# programs use the .NET Framework class library extensively to do common tasks and
provide various functionalities.
A data type defines the information that can be stored in a variable, the size of needed
memory and the operations that can be performed with the variable.
For example, to store an integer value (a whole number) in a variable, use the int keyword:int
myAge;
There are a number of built-in data types in C#. The most common are:
int - integer.
float - floating point number.
double - double-precision version of float.
char - a single character.
bool - Boolean that can have only one of two values: True or False.
string - a sequence of characters.
The statements below use C# data types:int x = 42;
double pi = 3.14;
char y = 'Z';
bool isOnline = true;
string firstName = "David".
Visual Studio will automatically generate some code for your project: using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SoloLearn
{
class Program
{
static void Main(string[] args)
{
}
}
}
You will learn what each of the statements does in the upcoming lessons.
For now, remember that every C# console application must contain a method (a function)
named Main. Main is the starting point of every application, i.e. the point where our program
starts execution from. This is a console window. As we did not have any statements in
our Main method, the program just produces a general message. Pressing any key will close
the console.
Most applications require some input from the user and give output as a result.
To display text to the console window you use
the Console.Write or Console.WriteLine methods. The difference between these two
is that Console.WriteLine is followed by a line terminator, which moves the cursor to
the next line after the text output.
The program below will display Hello World! to the console window:
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
}
Note the parentheses after the WriteLine method. This is the way to pass data, or
arguments, to methods. In our case WriteLine is the method and we pass "Hello
World!" to it as an argument. String arguments must be enclosed in quotation marks.
As you can see, the value of x replaced {0} and the value of y replaced {1}.
You can have as many variable placeholders as you need. (i.e.: {3}, {4}, etc.).
You can also prompt the user to enter data and then use
the Console.ReadLine method to assign the input to a string variable.
The following example asks the user for a name and then displays a message that
includes the input:
static void Main(string[] args)
{
string yourName;
Console.WriteLine("What is your name?");
yourName = Console.ReadLine();
If, in the program above, a non-integer value is entered (for example, letters),
the Convert will fail and cause an error.
Comments are explanatory statements that you can include in a program to benefit
the reader of your code.
The compiler ignores everything that appears in the comment, so none of that
information affects the result.
A comment beginning with two slashes (//) is called a single-line comment. The
slashes tell the compiler to ignore everything that follows, until the end of the line.
// Prints Hello
Console.WriteLine("Hello");
Comments are explanatory statements that you can include in a program to benefit
the reader of your code.
The compiler ignores everything that appears in the comment, so none of that
information affects the result.
A comment beginning with two slashes (//) is called a single-line comment. The
slashes tell the compiler to ignore everything that follows, until the end of the line.
// Prints Hello
Console.WriteLine("Hello");
A variable can be explicitly declared with its type before it is used.
Alternatively, C# provides a handy function to enable the compiler to determine the type of
the variable automatically based on the expression it is assigned to.
The var keyword is used for those scenarios:var num = 15;
The code above makes the compiler determine the type of the variable. Since the value
assigned to the variable is an integer, the variable will be declared as an integer
automatically.
Variables declared using the var keyword are called implicitly typed variables.
Implicitly typed variables must be initialized with a value.
For example, the following program will cause an error:
var num;
num = 42;
Although it is easy and convenient to declare variables using the var keyword,
overuse can harm the readability of your code. Best practice is to explicitly declare
variables.
Constants store a value that cannot be changed from their initial assignment.
To declare a constant, use the const modifier.
For example:const double PI = 3.14;
The value of const PI cannot be changed during program execution.
For example, an assignment statement later in the program will cause an error: const double
PI = 3.14;
PI = 8; //error
Constants must be initialized with a value when declared.
Operators
An operator is a symbol that performs mathematical or logical manipulations.
Arithmetic Operators
For example:
int x = 10;
int y = 4;
Console.WriteLine(x-y);
//Outputs 6
Assignment Operators
The same shorthand syntax applies to the multiplication, division, and modulus
operators.x *= 8; // equivalent to x = x * 8
x /= 5; // equivalent to x = x / 5
x %= 2; // equivalent to x = x % 2
Increment Operator
//Outputs 11
The increment operator has two forms, prefix and postfix.++x; //prefix
x++; //postfix
Prefix increments the value, and then proceeds with the expression.
Postfix evaluates the expression and then performs the incrementing.
Prefix example:
int x = 3;
int y = ++x;
// x is 4, y is 4
Postfix example:
int x = 3;
int y = x++;
// x is 4, y is 3
The prefix example increments the value of x, and then assigns it to y.
The postfix example assigns the value of x to y, and then increments x.
The decrement operator (--) works in much the same way as the increment operator, but
instead of increasing the value, it decreases it by one
.--x; // prefix
x--; // postfix
The if Statement
Relational Operators
Use relational operators to evaluate conditions. In addition to the less than (<) and
greater than (>) operators, the following operators are available:
Example:
if (a == b) {
Console.WriteLine("Equal");
}
// Displays Equal if the value of a is equal to the value of b
An optional else clause can be specified to execute a block of code when the
condition in the if statement evaluates to false.
Syntax:if (condition)
{
//statements
}
else
{
//statements
}
Nested if Statements
You can also include, or nest, if statements within another if statement.
For example:
int mark = 100;
/*Outputs
You passed.
Perfect!
*/
The if-else if statement can be used to decide among three or more actions.
For example:
int x = 33;
if (x == 8) {
Console.WriteLine("Value of x is 8");
}
else if (x == 18) {
Console.WriteLine("Value of x is 18");
}
else if (x == 33) {
Console.WriteLine("Value of x is 33");
}
else {
Console.WriteLine("No match");
}
//Outputs "Value of x is 33"
switch
The switch statement provides a more elegant way to test a variable for equality
against a list of values.
Each value is called a case, and the variable being switched on is checked for each
switch case.
For example:
int num = 3;
switch (num)
{
case 1:
Console.WriteLine("one");
break;
case 2:
Console.WriteLine("two");
break;
case 3:
Console.WriteLine("three");
break;
}
//Outputs "three"
In a switch statement, the optional default case is executed when none of the
previous cases match.
Example:
int age = 88;
switch (age) {
case 16:
Console.WriteLine("Too young");
break;
case 42:
Console.WriteLine("Adult");
break;
case 70:
Console.WriteLine("Senior");
break;
default:
Console.WriteLine("The default case");
break;
}
// Outputs "The default case"
We can shorten the previous example, by incrementing the value of num right in the
condition:
int num = 0;
while(++num < 6)
Console.WriteLine(num);
What do you think, is there a difference between while(num++ < 6) and while(++num
< 6)?
Yes! The loop while(++num < 6) will execute 5 times, because pre-increment
increases the value of x before checking the num < 6 condition, while post-increment
will check the condition before increasing the value of num, making while(num++ <
6) execute 6 times.
A for loop executes a set of statements a specific number of times, and has the
syntax:for ( init; condition; increment ) {
statement(s);
}
A counter is declared once in init.
Next, the condition evaluates the value of the counter and the body of the loop is
executed if the condition is true.
After loop execution, the increment statement updates the counter, also called the
loop control variable.
The condition is again evaluated, and the loop body repeats, only stopping when the
condition becomes false.
For example:
for (int x = 10; x < 15; x++)
{
Console.WriteLine("Value of x: {0}", x);
}
/*
Value of x: 10
Value of x: 11
Value of x: 12
Value of x: 13
Value of x: 14
*/
do-while
A do-while loop is similar to a while loop, except that a do-while loop is guaranteed
to execute at least one time.
For example:
int a = 0;
do {
Console.WriteLine(a);
a++;
} while(a < 5);
/* Outputs
0
1
2
3
4
*/
If the condition of the do-while loop evaluates to false, the statements in the do will
still run once:
int x = 42;
do {
Console.WriteLine(x);
x++;
} while(x < 10);
// Outputs 42
The do-while loop executes the statements at least once, and then tests the
condition.
The while loop executes the statement only after testing condition.
break
Console.WriteLine(num);
num++;
}
/* Outputs:
0
1
2
3
4
*/
If you are using nested loops (i.e., one loop inside another loop),
the break statement will stop the execution of the innermost loop and start
executing the next line of code after the block.
The continue statement is similar to the break statement, but instead of terminating
the loop entirely, it skips the current iteration of the loop and continues with the next
iteration.
For example:
for (int i = 0; i < 10; i++) {
if (i == 5)
continue;
Console.WriteLine(i);
}
/* Outputs:
0
1
2
3
4
6
7
8
9
*/
As you can see, number 5 is not printed, as the continue statement skips the
remaining statements of that iteration of the loop.
Logical Operators
Logical operators are used to join multiple expressions and return true or false.
The ? : Operator
Console.WriteLine(msg);
The code above checks the value of the age variable and displays the corresponding
message to the screen.
This can be done in a more elegant and shorter way by using the ?: operator, which
has the following form:Exp1 ? Exp2 : Exp3;
The ?: operator works the following way: Exp1 is evaluated. If it is true, then Exp2 is
evaluated and becomes the value of the entire expression. If Exp1 is false, then Exp3
is evaluated and its value becomes the value of the expression.
So, the example above can be replaced by the following:
int age = 42;
string msg;
msg = (age >= 18) ? "Welcome" : "Sorry";
Console.WriteLine(msg);
Now let's create a simple project that repeatedly asks the user to enter two values and then
displays their sum, until the user enters exit.
We start with a do-while loop that asks the user for input and calculates the sum:do {
Console.Write("x = ");
int x = Convert.ToInt32(Console.ReadLine());
Console.Write("y = ");
int y = Convert.ToInt32(Console.ReadLine());
Now let's create a simple project that repeatedly asks the user to enter two values and then
displays their sum, until the user enters exit.
We start with a do-while loop that asks the user for input and calculates the sum:
do {
Console.Write("x = ");
int x = Convert.ToInt32(Console.ReadLine());
Console.Write("y = ");
int y = Convert.ToInt32(Console.ReadLine());
What is a Method?
A method is a group of statements that perform a particular task.
In addition to the C# built-in methods, you may also define your own.
Declaring Methods
To use a method, you need to declare the method and then call it.
Each method declaration includes:
- the return type
- the method name
- an optional list of parameters.<return type> name(type1 par1, type2 par2, , typeN
parN)
{
List of statements
}
For example, the following method has an int parameter and returns the number
squared:int Sqr(int x)
{
int result = x*x;
return result;
}
The return type of a method is declared before its name. In the example above, the
return type is int, which indicates that the method returns an integer value. When
a method returns a value, it must include a return statement. Methods that return a
value are often used in assignment statements.
Occasionally, a method performs the desired operations without returning a value.
Such methods have a return type void. In this case, the method cannot be called as
part of an assignment statement.
void is a basic data type that defines a valueless state.
Calling Methods
Parameters are optional; that is, you can have a method with no parameters.
As an example, let's define a method that does not return a value, and just prints a line of text
to the screen.static void SayHi()
{
Console.WriteLine("Hello");
}
Our method, entitled SayHi, returns void, and has no parameters.
To execute a method, you simply call the method by using the name and any required
arguments in a statement.
The static keyword will be discussed later; it is used to make methods accessible in Main.
Calling Methods
Parameters
Parameters
Now you can call the method in Main and pass in the value for its parameters (also
called arguments):
The value 42 is passed to the method as an argument and is assigned to the formal
parameter x.
Parameters
You can pass different arguments to the same method as long as they are of the expected
type.
For example:
static void Func(int x)
{
Console.WriteLine(x*2);
}
static void Main(string[] args)
{
Func(5);
//Outputs 10
Func(12);
//Outputs 24
Func(42);
//Outputs 84
}
Multiple Parameters
You can have as many parameters as needed for a method by separating them
with commas in the definition.
Let's create a simple method that returns the sum of two parameters:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SoloLearn
class Program
{
return x+y;
Console.WriteLine(Sum(8, 6));
In the call above, the return value was displayed to the console window. Alternatively, we can
assign the return value to a variable, as in the code below:
You can add as many parameters to a single method as you want. If you have multiple
parameters, remember to separate them with commas, both when declaring them and when
calling the method.
Optional Arguments
When defining a method, you can specify a default value for optional parameters. Note that
optional parameters must be defined after required parameters. If corresponding arguments
are missing when the method is called, the method uses the default values.
To do this, assign values to the parameters in the method definition, as shown in this
example.static int Pow(int x, int y=2)
{
int result = 1;
for (int i = 0; i < y; i++)
{
result *= x;
}
return result;
}
The Pow method assigns a default value of 2 to the y parameter. If we call
the method without passing the value for the y parameter, the default value will be used.
Console.WriteLine(Pow(3, 4));
//Outputs 81
}
As you can see, default parameter values can be used for calling the same method in
different situations without requiring arguments for every parameter.
Just remember, that you must have the parameters with default values at the end of the
parameter list when defining the method.
Named Arguments
Named arguments free you from the need to remember the order of the parameters in
a methodcall. Each argument can be specified by the matching parameter name.
For example, the following method calculates the area of a rectangle by its height and
width:static int Area(int h, int w)
{
return h * w;
}
When calling the method, you can use the parameter names to provide the arguments in any
order you like:
Passing Arguments
There are three ways to pass arguments to a method when the method is called: By value,
By reference, and as Output.
By value copies the argument's value into the method's formal parameter. Here, we can
make changes to the parameter within the method without having any effect on
the argument.
By default, C# uses call by value to pass arguments.
The following example demonstrates by value:
Console.WriteLine(a); // Outputs 3
}
In this case, x is the parameter of the Sqr method and a is the actual argument passed into
the method.
As you can see, the Sqr method does not change the original value of the variable, as it is
passed by value, meaning that it operates on the value, not the actual variable.
Passing Arguments
There are three ways to pass arguments to a method when the method is called: By value,
By reference, and as Output.
By value copies the argument's value into the method's formal parameter. Here, we can
make changes to the parameter within the method without having any effect on
the argument.
By default, C# uses call by value to pass arguments.
The following example demonstrates by value:
Console.WriteLine(a); // Outputs 3
}
In this case, x is the parameter of the Sqr method and a is the actual argument passed into
the method.
As you can see, the Sqr method does not change the original value of the variable, as it is
passed by value, meaning that it operates on the value, not the actual variable .
Passing by Reference
Pass by reference copies an argument's memory address into the formal parameter. Inside
the method, the address is used to access the actual argument used in the call. This means
that changes made to the parameter affect the argument.
To pass the value by reference, the ref keyword is used in both the call and
the method definition:
The ref keyword passes the memory address to the method parameter, which allows
the methodto operate on the actual variable.
The ref keyword is used both when defining the method and when calling it.
Passing by Output
Output parameters are similar to reference parameters, except that they transfer data out of
the method rather than accept data in. They are defined using the out keyword.
The variable supplied for the output parameter need not be initialized since that value will
not be used. Output parameters are particularly useful when you need to return multiple
values from a method.
For example:
Unlike the previous reference type example, where the value 3 was referred to the method,
which changed its value to 9, output parameters get their value from the method (5 and 42 in
the above example).
Similar to the ref keyword, the out keyword is used both when defining the method and
when calling it.
Overloading
Method overloading is when multiple methods have the same name, but different
parameters.
For example, you might have a Print method that outputs its parameter to the console
window:
void Print(int a)
{
Console.WriteLine("Value: "+a);
}
The + operator is used to concatenate values. In this case, the value of a is joined to the text
"Value: ".
This method accepts an integer argument only.
Overloading it will make it available for other types, such as double:void Print(double a)
{
Console.WriteLine("Value: "+a);
}
Now, the same Print method name will work for both integers and doubles.
Overloading
When overloading methods, the definitions of the methods must differ from each other by
the types and/or number of parameters.
When there are overloaded methods, the method called is based on the arguments.
An integer argument will call the method implementation that accepts an integer parameter.
A double argument will call the implementation that accepts a double parameter. Multiple
arguments will call the implementation that accepts the same number of arguments.
Recursion
As you can see, a factorial can be thought of as repeatedly calculating num * num-1 until you
reach 1.
Based on this solution, let's define our method:static int Fact(int num) {
if (num == 1) {
return 1;
}
return num * Fact(num - 1);
}
In the Fact recursive method, the if statement defines the exit condition, a base case that
requires no recursion. In this case, when num equals one, the solution is simply to return 1
(the factorial of one is one).
The recursive call is placed after the exit condition and returns num multiplied by the
factorial of n-1.
For example, if you call the Fact method with the argument 4, it will execute as follows:
return 4*Fact(3), which is 4*3*Fact(2), which is 4*3*2*Fact(1), which is 4*3*2*1.
The factorial method calls itself, and then continues to do so, until the argument equals 1.
The exit condition prevents the method from calling itself indefinitely.
Classes
As we have seen in the previous modules, built-in data types are used to store a single value
in a declared variable. For example, int x stores an integer value in a variable named x.
In object-oriented programming, a class is a data type that defines a set of variables and
methods for a declared object.
For example, if you were to create a program that manages bank accounts,
a BankAccount class could be used to declare an object that would have all the properties
and methods needed for managing an individual bank account, such as a balance variable
and Deposit and Withdrawal methods.
A class is like a blueprint. It defines the data and behavior for a type. A class definition starts
with the keyword class followed by the class name. The class body contains the data and
actions enclosed by curly braces.class BankAccount
{
//variables, methods, etc.
}
The class defines a data type for objects, but it is not an object itself. An object is a concrete
entity based on a class, and is sometimes referred to as an instance of a class.
Value Types
Reference Types
Reference types are used for storing objects. For example, when you create an object of a
class, it is stored as a reference type.
Reference types are stored in a part of the memory called the heap.
When you instantiate an object, the data for that object is stored on the heap, while its heap
memory address is stored on the stack.
That is why it is called a reference type - it contains a reference (the memory address) to the
actual object on the heap.
As you can see, the p1 object of type Person on the stack stores the memory address of the
heap where the actual object is stored.
Stack is used for static memory allocation, which includes all your value types, like x.
Heap is used for dynamic memory allocation, which includes custom objects, that might
need additional memory during the runtime of your program.
Example of a Class
Now that we have our Person class defined, we can instantiate an object of that type in
Main.
The new operator instantiates an object and returns a reference to its location:
class Person {
int age;
string name;
public void SayHi() {
Console.WriteLine("Hi");
}
}
static void Main(string[] args)
{
Person p1 = new Person();
p1.SayHi();
}
//Outputs "Hi"
The code above declares a Person object named p1 and then calls
its public SayHi() method.
Notice the dot operator (.) that is used to access and call the method of the object.
Example of a Class
You can access all public members of a class using the dot operator.
Besides calling a method, you can use the dot operator to make an assignment when valid.
For example:
class Dog
{
public string name;
public int age;
}
static void Main(string[] args)
{
Dog bob = new Dog();
bob.name = "Bobby";
bob.age = 3;
Console.WriteLine(bob.age);
//Outputs 3
}
Encapsulation
Part of the meaning of the word encapsulation is the idea of "surrounding" an entity, not just
to keep what's inside together, but also to protect it.
In programming, encapsulation means more than simply combining members together
within a class; it also means restricting access to the inner workings of that class.
Encapsulation is implemented by using access modifiers. An access modifier defines the
scope and visibility of a class member.
Encapsulation is also called information hiding.
Encapsulation
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SoloLearn
{
class BankAccount {
balance += n;
balance -= n;
return balance;
class Program
b.Deposit(199);
b.Withdraw(42);
Console.WriteLine(b.GetBalance());
Constructors
A class constructor is a special member method of a class that is executed whenever a new
object of that class is created.
A constructor has exactly the same name as its class, is public, and does not have any
return type.
For example:class Person
{
private int age;
public Person()
{
Console.WriteLine("Hi there");
}
}
Now, upon the creation of an object of type Person, the constructor is automatically called.
Constructors
Constructors can be very useful for setting initial values for certain member variables.
A default constructor has no parameters. However, when needed, parameters can be added
to a constructor. This makes it possible to assign an initial value to an object when it's
created, as shown in the following example:
class Person
{
private int age;
private string name;
public Person(string nm)
{
name = nm;
}
public string getName()
{
return name;
}
}
static void Main(string[] args)
{
Person p = new Person("David");
Console.WriteLine(p.getName());
}
//Outputs "David"
Now, when the object is created, we can pass a parameter that will be assigned to
the name variable.
Constructors can be overloaded like any method by using different numbers of parameters.
Properties
Once the property is defined, we can use it to assign and read the private member:
class Person
{
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
}
static void Main(string[] args)
{
Person p = new Person();
p.Name = "Bob";
Console.WriteLine(p.Name);
}
The property is accessed by its name, just like any other public member of the class.
Properties
Properties
So, why use properties? Why not just declare the member variable public and access it
directly?
With properties you have the option to control the logic of accessing the variable.
For example, you can check if the value of age is greater than 0, before assigning it to the
variable:class Person
{
private int age=0;
public int Age
{
get { return age; }
set {
if (value > 0)
age = value;
}
}
}
You can have any custom logic with get and set accessors.
Auto-Implemented Properties
When you do not need any custom logic, C# provides a fast and effective mechanism for
declaring private members through their properties.
For example, to create a private member that can only be accessed through
the Name property's get and set accessors, use the following syntax:public string Name {
get; set; }
As you can see, you do not need to declare the private field name separately - it is created by
the property automatically. Name is called an auto-implemented property. Also called auto-
properties, they allow for easy and short declaration of private members.
We can rewrite the code from our previous example using an auto-property:
class Person
{
public string Name { get; set; }
}
static void Main(string[] args)
{
Person p = new Person();
p.Name = "Bob";
Console.WriteLine(p.Name);
}
// Outputs "Bob"
Arrays
We can provide initial values to the array when it is declared by using curly brackets:
string[ ] names = new string[3] {"John", "Mary", "Jessica"};
double[ ] prices = new double[4] {3.6, 9.8, 6.4, 5.9};
We can omit the size declaration when the number of elements are provided in the curly
braces:string[ ] names = new string[ ] {"John", "Mary", "Jessica"};
double[ ] prices = new double[ ] {3.6, 9.8, 6.4, 5.9};
We can even omit the new operator. The following statements are identical to the ones
above:string[ ] names = {"John", "Mary", "Jessica"};
double[ ] prices = {3.6, 9.8, 6.4, 5.9};
Array values should be provided in a comma separated list enclosed in {curly braces}.
Arrays
int[ ] myArray;
This statement declares an array of integers.
Since arrays are objects, we need to instantiate them with the new keyword:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SoloLearn
class Program
a[k] = k*2;
Console.WriteLine(a[k]);
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SoloLearn
class Program
a[k] = k*2;
foreach (int k in a) {
Console.WriteLine(k);
}
Multidimensional Arrays
Jagged Arrays
A jagged array is an array whose elements are arrays. So it is basically an array of arrays.
The following is a declaration of a single-dimensional array that has three elements, each of
which is a single-dimensional array of integers:int[ ][ ] jaggedArr = new int[3][ ];
Each dimension is an array, so you can also initialize the array upon declaration like this:int[ ]
[ ] jaggedArr = new int[ ][ ]
{
new int[ ] {1,8,2,7,9},
new int[ ] {2,4,6},
new int[ ] {33,42}
};
You can access individual array elements as shown in the example below:
Arrays Properties
The Array class in C# provides various properties and methods to work with arrays.
For example, the Length and Rank properties return the number of elements and the number
of dimensions of the array, respectively. You can access them using the dot syntax, just like
any class members:
Console.WriteLine(arr.Rank);
//Outputs 1
The Length property can be useful in for loops where you need to specify the number of
times the loop should run.
For example:
Array Methods
For example:
int[ ] arr = { 2, 4, 7, 1};
Console.WriteLine(arr.Max());
//Outputs 7
Console.WriteLine(arr.Min());
//Outputs 1
Console.WriteLine(arr.Sum());
//Outputs 14
C# also provides a static Array class with additional methods. You will learn about those in
the next module.
Strings
Its common to think of strings as arrays of characters. In reality, strings in C# are objects.
When you declare a string variable, you basically instantiate an object of type String.
String objects support a number of useful properties and methods:
Length returns the length of the string.
IndexOf(value) returns the index of the first occurrence of the value within the string.
Insert(index, value) inserts the value into the string starting from the specified index.
Remove(index) removes all characters in the string after the specified index.
Replace(oldValue, newValue) replaces the specified value in the string.
Substring(index, length) returns a substring of the specified length, starting from the
specified index. If length is not specified, the operation continues to the end of the string.
Contains(value) returns true if the string contains the specified value.
Console.WriteLine(a.IndexOf('t'));
//Outputs 5
if(a.Contains("some"))
Console.WriteLine("found");
//Outputs "found"
a = a.Remove(4);
Console.WriteLine(a);
//Outputs "I am"
a = a.Substring(2);
Console.WriteLine(a);
//Outputs "am"
You can also access characters of a string by its index, just like accessing elements of
an array:
Destructors
Lets include WriteLine statements in the destructor and constructor of our class and see
how the program behaves when an object of that class is created and when the program
ends:
class Dog
{
public Dog() {
Console.WriteLine("Constructor");
}
~Dog() {
Console.WriteLine("Destructor");
}
}
static void Main(string[] args) {
Dog d = new Dog();
}
/*Outputs:
Constructor
Destructor
/*
Static
Static
Because of their global nature, static members can be accessed directly using
the class name without an object.
For example:
class Cat {
public static int count=0;
public Cat() {
count++;
}
}
static void Main(string[] args)
{
Cat c1 = new Cat();
Cat c2 = new Cat();
Console.WriteLine(Cat.count);
}
//Outputs 2
As you can see, we can access the static variable using the class name: Cat.count.
The count variable is shared between all Cat objects. For this class, each time an object is
created, the static value is incremented. The program above demonstrates this when 2 is
displayed after creating two objects of that class.
You must access static members using the class name. If you try to access them via an
object of that class, you will generate an error.
Static Methods
class Dog
{
public static void Bark() {
Console.WriteLine("Woof");
}
}
static void Main(string[] args)
{
Dog.Bark();
}
// Outputs "Woof"
Static
As you can see, we access the property ONE using the name of the class, just like
a staticmember. This is because all const members are static by default.
Static Constructors
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SoloLearn
class Program
class SomeClass {
static SomeClass() {
X = 10;
Y = 20;
Console.WriteLine(SomeClass.X);
The constructor will get called once when we try to access SomeClass.X or SomeClass.Y.
Static Classes
Console.WriteLine(Math.Pow(2, 3));
//Outputs 8
You access all members of the Math class using the class name, without declaring an
object.
Tap next to learn about the available methods of the Math class.
Static Classes
There are a number of useful static methods and properties available in C#:
Math
Array
The Array class includes some static methods for manipulating arrays:int[] arr = {1, 2, 3, 4};
Array.Reverse(arr);
//arr = {4, 3, 2, 1}
Array.Sort(arr);
//arr = {1, 2, 3, 4}
String
DateTime
DateTime.DaysInMonth(2016, 2);
//return the number of days in the specified month
The Console class is also an example of a static class. We use
its static WriteLine()method to output to the screen, or the static ReadLine() method to get
user input.
The Convert class used to convert value types is also a static class.
The this keyword is used inside the class and refers to the current instance of the class,
meaning it refers to the current object.
One of the common uses of this is to distinguish class members from other data, such as
local or formal parameters of a method, as shown in the following example:class Person {
private string name;
public Person(string name) {
this.name = name;
}
}
Here, this.name represents the member of the class, whereas name represents the
parameter of the constructor.
Another common use of this is for passing the current instance to a method as parameter:
ShowPersonInfo(this);
The readonly modifier prevents a member of a class from being modified after construction.
It means that the field declared as readonly can be modified only when you declare it or from
within a constructor.
For example:class Person {
private readonly string name = "John";
public Person(string name) {
this.name = name;
}
}
If we try to modify the name field anywhere else, we will get an error.
There are three major differences between readonly and const fields.
First, a constant field must be initialized when it is declared, whereas a readonly field can be
declared without initialization, as in:readonly string name; // OK
const double PI; // Error
Second, a readonly field value can be changed in a constructor, but a constant value cannot.
Third, the readonly field can be assigned a value that is a result of a calculation, but
constants cannot, as in:readonly double a = Math.Sin(60); // OK
const double b = Math.Sin(60); // Error!
Indexers
Arrays use integer indexes, but indexers can use any type of index, such as strings,
characters, etc.
Indexers
class Clients {
private string[] names = new string[10];
Console.WriteLine(c[1]);
//Outputs "Bob
You typically use an indexer if the class represents a list, collection, or array of objects.
Operator Overloading
Most operators in C# can be overloaded, meaning they can be redefined for custom actions.
For example, you can redefine the action of the plus (+) operator in a custom class.
Consider the Box class that has Height and Width properties:
class Box {
public int Height {get; set;}
public int Width {get; set;}
public Box(int h, int w) {
Height = h;
Width = w;
}
}
static void Main(string[] args) {
Box b1 = new Box(14, 3);
Box b2 = new Box(5, 7);
}
We would like to add these two Box objects, which would result in a new, bigger Box.
So, basically, we would like the following code to work: Box b3 = b1 + b2;
The Height and Width properties of object b3 should be equal to the sum of the
corresponding properties of the b1 and b2 objects.
This is achieved through operator overloading. Tap next to learn more!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SoloLearn
class Program
class Box {
Height = h;
Width = w;
return res;
Box b3 = b1 + b2;
Console.WriteLine(b3.Height);
Console.WriteLine(b3.Width);
}
}
Inheritance
Inheritance allows us to define a class based on another class. This makes creating and
maintaining an application easy.
The class whose properties are inherited by another class is called the Base class. The class
which inherits the properties is called the Derived class.
For example, base class Animal can be used to derive Cat and Dog classes.
The derived class inherits all the features from the base class, and can have its own
additional features.
Inheritance
d.Bark();
//Outputs "Woof"
}
A base class can have multiple derived classes. For example, a Cat class can inherit
from Animal.
Inheritance allows the derived class to reuse the code in the base class without having to
rewrite it. And the derived class can be customized by adding more members. In this
manner, the derived class extends the functionality of the base class.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SoloLearn
class Program
class Person {
int number;
s.Speak();
We created a Student object and called the Speak method, which was declared in the base
class Person.
C# does not support multiple inheritance, so you cannot inherit from multiple classes.
However, you can use interfaces to implement multiple inheritance. You will learn more
about interfaces in the coming lessons.
protected
Up to this point, we have worked exclusively with public and private access modifiers.
Public members may be accessed from anywhere outside of the class, while access
to privatemembers is limited to their class.
The protected access modifier is very similar to private with one difference; it can be
accessed in the derived classes. So, a protected member is accessible only from derived
classes.
For example:
class Person {
protected int Age {get; set;}
protected string Name {get; set;}
}
class Student : Person {
public Student(string nm) {
Name = nm;
}
public void Speak() {
Console.Write("Name: "+Name);
}
}
static void Main(string[] args) {
Student s = new Student("David");
s.Speak();
//Outputs "Name: David"
}
As you can see, we can access and modify the Name property of the base class from the
derived class.
But, if we try to access it from outside code, we will get an error: