Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 40

Sololearn C#

Basic Concepts

C# is an object-oriented language that runs on the .NET Framework.


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, provides core services such as memory management, code accuracy and many
other aspects.
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.
Applications written in C# use the .NET Framework and its components.

A variable name, also called an identifier, can contain letters, numbers, and the underscore
character but may not start with a number. The best identifiers are descriptive.
A line of code that completes an action is called a statement. Each statement in C# must end with
a semicolon.
Data types: int, float, double, char – ‘’, string – “”, bool.
Char variables use single quotes and string variables use double quotes.

You can use visual studio to create C# applications.


Every C# console application must contain a method named Main. This is the starting point of
every application.
To run your program use Ctrl+F5

Console.WriteLine() method will write text to the console followed by a line terminator, which
moves the cursor to the next line after the text output.
Console.Write() method will write text to the console but is not followed by a line terminator.
Variables can be displayed to the console window and strings can even be formatted using the
following syntax:
static void Main(string[] args)
{
int x = 10;
double y = 20;

Console.WriteLine("x = {0}; y = {1}", x, y);


}
// Output: x = 10; y = 20

Console.ReadLine() method assigns user input to a variable, it returns a string variable.


To convert to a specific type the Convert.ToXXX() methods must be used. These include:
Convert.ToDouble(), Convert.ToBoolean().
For integer conversion there are three alternatives available based on the bit size of the integer:
Convert.ToInt16(), Convert.ToInt32, Convert.ToInt64. Default is 32.
// is a single line comment
/*
Is a multi
Line
comment
*/

C# provides a function to enable the compiler to determine the type of the variable automatically
based on the expression it is assigned to, the var keyword:
var num = 15;
// assigns to integer automatically since the value is an integer
Variables declared using the var keyword are called implicitly typed variables. Implicitly typed
variables must be initialized with a value, therefore the following code will cause an error:
var num;
num = 42;
It is best practice to explicitly declare variables.

Constants store a value that cannot be changed from their initial assignment, to declare use the
const modifier:
const double PI = 3.14;
Constants must be initialized with a value when declared, trying to change the value of a constant
later will cause an error.

C# supports: +, -, *, /, %.
With the division operator if both operands are integers any remainder is dropped in order to return
an integer value.
Division by 0 is undefined and will crash your program.
Operator precedence exists.

C# has compound assignment operators like +=, -=, *=, /= and %=.
C# has increment and deincrement, ++ and --.
These have two forms, prefix and postfix.
++x; // prefix
x++; // postfix
prefix increments the value, and then proceeds with the expression
postfix evaluates the expression them performs incrementing.
Postfix example:
int x = 3;
int y = x++;
// x is 4, y is 3
Decrement, --, works the same way.
Conditionals and Loops

If statement:
if (condition)
{
// Execute this code when condition is true
} else if (condition) {
// Execute this code when condition is true
} else {
// Execute this code when all other conditions are false
}
These can use relational operators: >=, <=, == and !=
If statements can be nested.

Switch statement, used to test a variable for equality against a list of values:
int num = 3;
switch (num)
{
case 1:
Console.WriteLine("one");
break; // prevents from checking for other cases,
terminates the switch statement.
case 2:
Console.WriteLine("two");
break;
case 3:
Console.WriteLine("three");
break;
default: // executes when none of the cases matches the switch
expression
Console.WriteLine(“zero”);
break;
}
//Outputs "three"
C# does not allow fall through, and as such all case and default code must end with a break
statement. To allow a fall through you can use goto case like:
switch (/*...*/) {
case 0: // shares the exact same code as case 1
case 1:
// do something
goto case 2;
case 2:
// do something else
goto default;
default:
// do something entirely different
break;
} // as you can see a fall through has been implemented
C# compilers will not compile code if code falls through except by the above method.
While Loop, repeatedly executes a block of code as long as a given condition is true:
int num = 1;
while(num < 6)
{
Console.WriteLine(num);
num++;
}
/* Outputs
1
2
3
4
5
*/
Without a statement that eventually evaluates the loop condition to false, the loop will be infinite.
A loop condition can be incremented within the condition parentheses:
int num = 0;
while(++num < 6)
Console.WriteLine(num);

For Loop, executes a set of statements a specific number of times:


for ( init; condition; increment ) {
statement(s);
}
// 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
*/
The init and increment statements may be left out if not needed but remember semicolons are
mandatory:
int x = 10;
for ( ; x > 0 ; )
{
Console.WriteLine(x);
x -= 3;
}
For (; ;) {} is an infinite loop
Do-While Loop, like a while loop with the condition at the end and is guaranteed to execute at
least one time:
int a = 0;
do {
Console.WriteLine(a);
a++;
} while(a < 5);

/* Outputs
0
1
2
3
4
*/
It is important that you add a semicolon after the while loop

break; can be used in loops to immediately terminate a loop, example:


int num = 0;
while (num < 20)
{
if (num == 5)
break;

Console.WriteLine(num);
num++;
}

/* Outputs:
0
1
2
3
4
*/
If using nested loops, the break statement will stop the execution of the innermost loop and start
executing the next line of code after the block.
Continue will skip the current iteration of the loop and continue with the next iteration, 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
*/

Logical operators are used to join multiple expressions and return true or false.
&& AND, || OR and ! NOT.

Ternary Operator, takes 3 arguments and is like a shortened if-else statement:


int age = 42;
string msg;
msg = (age >= 18) ? "Welcome" : "Sorry";
// if true then first else second
Console.WriteLine(msg);
Methods

A method is a group of statements that perform a particular task. Advantages:


-Reusable code
-Easy to test
-Modifications to a method do not affect the calling program
-One method can accept many different inputs
Every valid C# program has at least one method, the Main method.
<return type> name(type1 par1, type2 par2, … , typeN parN)
{
List of statements
}

int Sqr(int x) // if returning none use void


{
int result = x*x;
return result;
}
You can define a method with no parameters.

Parameters in a method are created upon entering the method and destroyed upon exiting the
method. Parameters are the variables that accept the values (arguments) passed to the method.

Return values using the return statement.

You can specify default values for the parameters. You must have the parameters with default
values at the end of the parameter list when defining the method.
Named arguments allow you to specify an argument for a particular parameter, does not require
you to know the order in which they exist:
static int Area(int h, int w)
{
return h * w;
}
static void Main(string[] args)
{
int res = Area(w: 5, h: 8);
Console.WriteLine(res);
//Outputs 40
}
Passing an argument by value (the normal way) does not change the original value of the variable,
it operates on the value.
static void Sqr(int x)
{
x = x * x;
}
static void Main()
{
int a = 3;
Sqr(a);

Console.WriteLine(a); // Outputs 3
}
Passing an argument by reference copies an arguments memory address into the formal
parameter. Inside the method the address is used to access the actual argument used in the call.
The original variable used for the argument is therefore changed/operated on.
static void Sqr(ref int x)
{
x = x * x;
}
static void Main()
{
int a = 3;
Sqr(ref a);

Console.WriteLine(a); // Outputs 9
}
Passing by output transfers the data out of the method rather than accept data in. The variable
used for the output parameter does not need to be initialized since that value will not be used.
Useful if you want to return multiple values from a method.
static void GetValues(out int x, out int y)
{
x = 5;
y = 42;
}
static void Main(string[] args)
{
int a, b;
GetValues(out a, out b);
//Now a equals 5, b equals 42
}
Method overloading, multiple methods have the same name but different parameters.
You cannon overload method declarations that differ only by return type.
static void Print(int a) {
Console.WriteLine("Value: " + a);
}
static void Print(double a) {
Console.WriteLine("Value: " + a);
}
static void Print(string label, double a) {
Console.WriteLine(label + a);
}

static void Main(string[] args) {


Print(11);
Print(4.13);
Print("Average: ", 7.57);
}

A recursive method is a method that calls itself. Calculating the factorial of a number is a good
example.
static int Fact(int num) {
if (num == 1) {
return 1;
}
return num * Fact(num - 1);
}
static void Main(string[] args)
{
Console.WriteLine(Fact(6));
//Outputs 720
}
The if statement is the exit condition, when achieved the method will unwind.

Making a pyramid:
static void DrawPyramid(int n)
{
for (int i = 1; i <= n; i++)
{
for (int j = i; j <= n; j++)
{
Console.Write(" ");
}
for (int k = 1; k <= 2 * i - 1; k++)
{
Console.Write("*" + " ");
}
Console.WriteLine();
}
}
Classes and Objects

A class is a data type that defines a set of variables and methods for a declared object. A class is
like a blueprint, it defines the data and behaviour for a type. A class definition:
class BankAccount
{
//variables, methods, etc.
}
The class 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.
In programming, the term type is used to refer to a class name: We’re creating an object of a
particular type. Creating an object is called instantiation.
The characteristics of an object are called properties.

C# has two ways of storing data: by reference and by value. The built-in data types, such as int
and double, are used to declare variables that are value types. Their value is stored in memory in
a location called the stack.
Reference types are used for storing objects, so when you create an object of a class it is stored
as a reference type. Reference types are stored in 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.

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 variables.
Heap is used for dynamic memory allocation, including objects, that might need additional memory
during the runtime of your program.
Access modifiers are keywords that are used to specify the accessibility of a method (also called a
member).
A member that has been defined public can be accessed from outside the class, as long as it’s
anywhere within the scope of the class object. The default access modifier is private – only
accessible within the class.
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"
Use the dot operator to access members of a class or to make an assignment to an attribute of an
object.
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 is also called information hiding. Encapsulation is implemented by using access
modifiers to define the scope and visibility of a class member.
C# supports the following access modifiers:
Public-accessible from outside the class
Private-default, only accessible within class and hides them from outside
Protected-only accessible within class and subclasses
Internal-only accessible within files in the same assembly
Protected Internal-only accessible within files in the same assembly or from a derived class in
another assembly.
class BankAccount
{
private double balance=0;
public void Deposit(double n)
{
balance += n;
}
public void Withdraw(double n)
{
balance -= n;
}
public double GetBalance()
{
return balance;
}
}
Providing getters and setters for private variable balance.
Encapsulation allows you to control the way data is accessed or modified, make code more
flexible and easy to change and to change one part of the code without affecting other parts of
code.

Properties in C# are members that provide a flexible mechanism to read, write or compute the
value of a private field. They include special methods called accessors that contains the
executable statements that the property uses.

class Person
{
private string name; //field

public string Name //property


{
get { return name; }
set { name = value; }
}
}

Value is a special keyword that represents the value we assign to a property using the set
accessor. Convention indicates that properties have the same name as the private field with a
capital letter. You can omit any accessor of a property or make a accessor private.
You can declare private members through their properties quickly with an auto-implemented
property.
public string Name { get; set; }
You do not need to declare the private field name separately-it is created by the property
automatically.
Arrays & Strings

An array is a collection of variables of the same type.


int[] myArray;
int[] myArray = new int[5]; // int array of size 5
Use curly brackets to provide initial values:
string[ ] names = {"John", "Mary", "Jessica"};
double[ ] prices = {3.6, 9.8, 6.4, 5.9};

you can interate through arrays using loops by going through its indexes.
int[ ] a = new int[10];
for (int k = 0; k < 10; k++) {
a[k] = k*2;
}
For each loop provides a shorter and easier way of accessing array elements.
foreach (int k in a) {
Console.WriteLine(k);
}
If you do not explicitly know the type of the array you can use var instead:
foreach (var k in a) {
Console.WriteLine(k);
}

Arrays can be multi-dimensional


type[, , … ,] arrayName = new type[size1, size2, …, sizeN];
int[ , ] x = new int[3,4];
They can be initialized in the same way

A jagged array is an array whose elements are arrays-an array of arrays.


int[ ][ ] jaggedArr = new int[3][ ];
Each dimension is an array so you can initialize the array upon declaration:
int[ ][ ] jaggedArr = new int[ ][ ]
{
new int[ ] {1,8,2,7,9},
new int[ ] {2,4,6},
new int[ ] {33,42}
};
Access individual array elements like:
int x = jaggedArr[2][1]; //42
A jagged array is an array-of-arrays, each of which can be of different lengths and occupy their
own block in memory.
A multidimensional array is a single block of memory. It always has the same amount of columns
for every row.
Research on jagged array vs multidimensional array:
https://www.youtube.com/watch?v=3UcJGikWJxs
C# provides properties and methods to work with arrays.
Length and Rank properties return the number of elements and number of dimensions of the
array.
int[ ] arr = {2, 4, 7};
Console.WriteLine(arr.Length);
//Outputs 3

Console.WriteLine(arr.Rank);
//Outputs 1
Length property is useful in for loops:
int[ ] arr = {2, 4, 7};
for(int k=0; k<arr.Length; k++) {
Console.WriteLine(arr[k]);
}
Max() and Min() returns the largest and smallest value respectively. Sum() returns sum of all
elements.

Strings in C# are objects. Strings have properties and methods.


Length property returns length of string.
IndexOf(value) returns index of first occurrence.
Insert(index, value) inserts value into string starting from specified index.
Remove(index) removes all characters in the string after specified index.
Replace(oldValue, newValue) replaces the specified value
Substring(index, length) returns substring, if length not specified assumed infinite.
Constains(value) returns true if contains specified value.
string a = "some text";
Console.WriteLine(a.Length);
//Outputs 9

Console.WriteLine(a.IndexOf('t'));
//Outputs 5

a = a.Insert(0, "This is ");


Console.WriteLine(a);
//Outputs "This is some text"

a = a.Replace("This is", "I am");


Console.WriteLine(a);
//Outputs "I am some text"

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, like in an array.
string a = "some text";
Console.WriteLine(a[2]);
//Outputs "m"
More On Classes

Destructors are automatically invoked when an object is destroyed or deleted. They have the
following attributes:
A class can only have one destructor, they cannot be called but are invoked automatically, they do
not take modifiers or parameters, the name of a destructor is exactly the same as the class
prefixed with a tilde (~).
class Dog
{
~Dog()
{
// code statements
}
}
They are useful for releasing resources before coming out of the program, such as closing files,
releasing memory, etc.

Class members (variables, properties and methods) can be declared as static. This means that
the members belong to the class instead of a specific instance. There is only one copy of the static
member.
class Cat {
public static int count=0;
public Cat() {
count++; // to count the amount of cat instances created
}
}
They can be accessed directly using the class name without an object.
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
The same goes for static methods:
class Dog
{
public static void Bark() {
Console.WriteLine("Woof");
}
}
static void Main(string[] args)
{
Dog.Bark();
}
// Outputs "Woof"
Static methods can only access static members. Any method called directly from Main has to be
static.
Constant members are static by definition.
class MathClass {
public const int ONE = 1;
}
static void Main(string[] args) {
Console.Write(MathClass.ONE);
}
//Outputs 1
We can access property ONE using the name of the class, just like a static member.
Constructors can be declared static to initialize static members of the class. The static constructor
is automatically called once when we access a static member of the class.
class SomeClass {
public static int X { get; set; }
public static int Y { get; set; }

static SomeClass() {
X = 10;
Y = 20;
}
}

A static class can only contain static members. You cannot instantiate an object of a static class
as only one instance of the static class can exist in a program. They are useful for combining
logical properties and methods, a good examples is the Math class. You can access all members
of the math class using the class name with no declaration.
There are a number of useful static methods and properties available in C#.
Math.PI constant PI
Math.E logarithmic base e
Math.Max() larger of two arguments
Math.Min() smaller
Math.Abs() absolute value
Math.Sin() sine of angle
Math.Cos() cosine of angle
Math.Pow() number raised to specified power
Math.Round() round decimal to integer
Math.Sqrt() square root of specified number.
Array.Reverse(arr) reverse array
Array.Sort(arr) sort array
String.Concat(s1, s2) combine two strings
String.Equals(s1, s2) returns true or false.
DateTime structure allows you to work with dates:
DateTime.Now; represents current date and time
DateTime.Today; represents current day
DateTime.DaysInMonth(2016,2); // returns number of days in the specified month.
Console and Covert are static classes.

The this keyword is used inside the class and refers to the current instance of the class, meaning it
refers to the current object. We can use it to distinguish class members from other data. We can
also use this to pass the current instance to a method as a parameter.
class Person {
private string name;
public Person(string name) {
this.name = name;
}
}
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:
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:
 A readonly field can be declared without initialization but a constant field must be initialized
 A readonly field can be changed in a constructor, a constant field can not
 A readonly field can be assigned a value that is a result of a calculation but constants cannot
The readonly modifier prevents a member of a class from being modified after construction.
An indexer allows objects to be indexed like an array. The string class implements an indexer so
we can access any character (Char object) by its index.
string str = "Hello World";
char x = str[4];
Console.WriteLine(x);
//Outputs "o"
Arrays use integer indexes, but indexers can use any type of index, such as strings, characters
etc. The declaration of an indexer is similar to a property. However indexers accessors require an
index. You use get and set accessors for defining an indexer, indexers return or set a particular
value from the object instance. Indexers are defined with the this keyword.
Example:
class Clients {
private string[] names = new string[10];

public string this[int index] {


get {
return names[index];
}
set {
names[index] = value;
}
}
}
When we declare an object of class Clients, we use an index to refer to specific objects like the
elements of an array:
Clients c = new Clients();
c[0] = "Dave";
c[1] = "Bob";

Console.WriteLine(c[1]);
//Outputs "Bob"
You use an indexer if the class represents a list, collection or array of objects.

Most operators in C# can be overloaded, they can be redefined for custom actions.
For example, you can redefine the action of the plus (+) operator in a custom class.
Consider box class that has a height and width.
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 want to add two boxes together to make a larger box. So this code should work:
Box b3 = b1 + b2;
Overloaded operators are methods with special names, where they keyword operator is followed
by the symbol for the operator being defined. It has a return type and a parameter list. For
example, for our Box class, we overload the + operator:
public static Box operator+ (Box a, Box b) {
int h = a.Height + b.Height;
int w = a.Width + b.Width;
Box res = new Box(h, w);
return res;
}
The overloaded operator must be static. Now this code works:
static void Main(string[] args) {
Box b1 = new Box(14, 3);
Box b2 = new Box(5, 7);
Box b3 = b1 + b2;

Console.WriteLine(b3.Height); //19
Console.WriteLine(b3.Width); //10
}
All arithmetic and comparison operators can be overloaded.
Inheritance & Polymorphism

Inheritance allows us to define a class based on another class. This makes creating and maintain
an application easy. A derived class inherits from a base class. The derived class inherits all the
features from the base class and can have its own additional features.
Inheritance allows us to define a class based on another class.
class Dog : Animal {
public Dog() {
Legs = 4;
}
public void Bark() {
Console.Write("Woof");
}
}
A colon and the name of the base class follow the name of the derived class. All public members
of Animal become public members of Dog. That is why we can access the Legs member in the
Dog constructor.
A base class can have multiple derived classes. Inheritance allows the derived class to reuse the
code in the base class without having to rewrite it. You can add more members to the derived
class.
C# does not support multiple inheritance, so you cannot inherit from multiple classes. However
you can use interfaces to implement multiple inheritance.

Protected access modifier can be accessed in the class and subclasses. This means that
protected members are accessible to derived classes.
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"
}
A class can prevent other classes from inheriting it, or any of its members, using the sealed
modifier:
sealed class Animal {
//some code
}
class Dog : Animal { } //Error
With inheritance, the base class constructor and destructor are not inherited, so you should define
constructors for the derived classes. However the base class constructor and destructor are being
invoked automatically when an object of the derived class is created or deleted. Consider:
class Animal {
public Animal() {
Console.WriteLine("Animal created");
}
~Animal() {
Console.WriteLine("Animal deleted");
}
}
class Dog: Animal {
public Dog() {
Console.WriteLine("Dog created");
}
~Dog() {
Console.WriteLine("Dog deleted");
}
}
Creating a Dog object:
static void Main(string[] args) {
Dog d = new Dog();
}
/*Outputs
Animal created
Dog created
Dog deleted
Animal deleted
*/
The base class constructor is called first and the derived class constructor is called next. The
derived class needs it base class in order to work, which is why the base class constructor is
called first.

Polymorphism means “having many forms”. It typically occurs when there is a hierarchy of classes
and they are related through inheritance from a common base class.
Polymorphism means that a call to a member method will cause a different implementation to be
executed depending on the type of object that invokes the method. It means that a single method
can have a number of different implementations.
The virtual keyword allows methods to be overridden in derived classes:
class Shape {
public virtual void Draw() { // in subclasses draw can be overriden
Console.Write("Base Draw");
}
}
Virtual methods enable you to work with groups of related objects in a uniform way.
We can use the override keyword to allow subclasses to have their own custom methods different
from the base classes:
class Circle : Shape {
public override void Draw() {
// draw a circle...
Console.WriteLine("Circle Draw");
}
}
class Rectangle : Shape {
public override void Draw() {
// draw a rectangle...
Console.WriteLine("Rect Draw");
}
}
Polymorphism is a way to call the same method for different objects and generate different results
based on the object type. The polymorphic approach allows us to treat each object the same way.
The abstract modifier indicates that the thing being modified has a missing or incomplete
implementation. These specify that the derived classes must define that method on their own.
Abstract modifiers can only be used in abstract classes as you cannot create objects of a class
containing an abstract method.
abstract class Shape {
public abstract void Draw();
}
A abstract method does not need curly brackets. Members marked as abstract must be
implemented by classes that derive from the abstract class. An abstract class can have multiple
abstract members.
An abstract class is intended to be a base class of other classes, as such it acts like a template for
its derived classes.
abstract class Shape {
public abstract void Draw();
}
class Circle : Shape {
public override void Draw() {
Console.WriteLine("Circle Draw");
}
}
class Rectangle : Shape {
public override void Draw() {
Console.WriteLine("Rect Draw");
}
}
static void Main(string[] args) {
Shape c = new Circle();
c.Draw();
//Outputs "Circle Draw"
}
Abstract classes have the following features:
 They cannot be instantiated
 They may only contain abstract methods and accessors
 A derived class from an abstract class must include actual implementation of all inherited
abstract methods and accessors.
 The sealed modifier cannot be used as it is the opposite of abstract.
An interface is a completely abstract class, which contains only abstract members. It is declared
using the interface keyword:
public interface IShape
{
void Draw();
}
All members of the interface are by default abstract so no need to use the abstract keyword. Also
all members are always public and no access modifiers can be applied to them. It is convention to
use the capital letter I as the starting letter for an interface name. They can contain properties,
methods, etc. but cannot contain fields.
A class implementing an interface must implement all of its methods. The interface simply
describes what a class should do. The class implementing the interface must define how to
accomplish the behaviours. The syntax is the same as deriving from a class:
public interface IShape {
void Draw();
}
class Circle : IShape {
public void Draw() {
Console.WriteLine("Circle Draw");
}
}
static void Main(string[] args) {
IShape c = new Circle();
c.Draw();
//Outputs "Circle Draw"
}
Note that the override keyword is not needed when implementing an interface.
A class can implement multiple interfaces compared to one base class. Therefore you can include
behaviour from multiple sources. To implement multiple interfaces separate them with commas.

C# supports nested classes: a class that is a member of another class.


class Car {
string name;
public Car(string nm) {
name = nm;
Motor m = new Motor();
}
public class Motor {
// some code
}
}
The Motor class can be used similar to other members of the class. A nested class acts as a
member of the class, so it can have access modifiers.
Namespaces declare a scope that contains a set of related objects. You can use a namespace to
organize code elements. The using keyword states that the program is using a given namespace.
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) {
}
}
}
Without the using statement, we would have to specify the namespace wherever it is used:
System.Console.WriteLine("Hi");
The .NET Framework uses namespaces to organize its many classes. System is one example of a
.NET Framework namespace. Namespaces can help you group your class and method names in
larger programming projects.
Structs, Enums, Exceptions & Files

A struct type is a value type that is typically used to encapsulate small groups of related variables.
struct Book {
public string title;
public double price;
public string author;
}
Structs share most of the same syntax as classes, but are more limited than classes. Unlike
classes, structs can be instantiated without using a new operator.
static void Main(string[] args) {
Book b;
b.title = "Test";
b.price = 5.99;
b.author = "David";

Console.WriteLine(b.title);
//Outputs "Test"
}
Structs do not support inheritance and cannot contain virtual methods.
Structs can contain methods, properties, indexers, and so on. They cannot contain default
constructors (a constructor without parameters), but they can have constructors that take
parameters. In that case the new keyword is used to instantiate a struct object.
struct Point {
public int x;
public int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
static void Main(string[] args) {
Point p = new Point(10, 15);
Console.WriteLine(p.x);
// Outputs 10
}
Structs are best suited for small data structures that contain primarily data that is not intended to
be modified after the struct is created. All standard C# types (int, double, bool, char, etc.) are
actually structs.
The enum keyword is used to declare an enumeration: a type that consists of a set of named
constants called the enumerator list. By default, the first enumerator has the value 0, and the value
of each successive enumerator is increased by 1.
enum Days {Sun, Mon, Tue, Wed, Thu, Fri, Sat};
You can also assign your own enumerator values:
enum Days {Sun, Mon, Tue=4, Wed, Thu, Fri, Sat};
Wed is 5 as the value of the next item in an Enum is one increment of the previous value. You can
refer to the values in the Enum with the dot syntax. In order to assign the Enum values to int
variables, you have to specify the type in parentheses:
enum Days { Sun, Mon, Tue, Wed, Thu, Fri, Sat };

static void Main(string[] args) {


int x = (int)Days.Tue;
Console.WriteLine(x);
//Outputs 2
}
Enums define variables that represent members of a fixed set.
Enums are often used with switch statements:
enum TrafficLights { Green, Red, Yellow };

static void Main(string[] args) {


TrafficLights x = TrafficLights.Red;
switch (x) {
case TrafficLights.Green:
Console.WriteLine("Go!");
break;
case TrafficLights.Red:
Console.WriteLine("Stop!");
break;
case TrafficLights.Yellow:
Console.WriteLine("Caution!");
break;
}
//Outputs "Stop!"
}
An exception is a problem that occurs during program execution, they cause abnormal termination
of the program. An exception can occur for many different reasons, examples:
 Invalid data
 File does not exist
 No network connection
 Stack overflow
Three types of errors: syntax errors, runtime errors, and logic errors.
C# has the try-catch statement to handle exceptions so that a program wont crash when an error
occurs:
try {
int[] arr = new int[] { 4, 5, 8 };
Console.Write(arr[8]);
}
catch(Exception e) {
Console.WriteLine("An error occurred");
}
//Outputs "An error occurred"
The code that might generate the exception is placed in the try block. If an exception occurs, the
catch blocks is executed without stopping the program. We use the general Exception type to
handle all kinds of exceptions. We can also use the exception object e to access the exception
details, such as the original error message (e.Message).
try {
int[] arr = new int[] { 4, 5, 8 };
Console.Write(arr[8]);
}
catch(Exception e) {
Console.WriteLine(e.Message);
}
// Index was outside the bounds of the array.
A single try block can contain multiple catch blocks that handle different exceptions separately.
int x, y;
try {
x = Convert.ToInt32(Console.Read());
y = Convert.ToInt32(Console.Read());
Console.WriteLine(x / y);
}
catch (DivideByZeroException e) {
Console.WriteLine("Cannot divide by 0");
}
catch(Exception e) {
Console.WriteLine("An error occurred");
}
The last catch handles all the other exceptions that might occur. The Exception type must be
defined last.
An optional finally block can be used after the catch blocks. The finally block is used to execute a
given set of statements, whether an exception is thrown or not.
int result=0;
int num1 = 8;
int num2 = 4;
try {
result = num1 / num2;
}
catch (DivideByZeroException e) {
Console.WriteLine("Error");
}
finally {
Console.WriteLine(result);
}

The System.IO namespace has various classes that are used for operations with files. The File
class is one of them:
string str = "Some text";
File.WriteAllText("test.txt", str);
The WriteAllText() method creates a file with the specified path and writes the content to it. If the
file already exists, it is overwritten. To use the File class you need to use the System.IO
namespace: using System.IO;
You can read the content of a file using the ReadAllText method of the File class:
string txt = File.ReadAllText("test.txt");
Console.WriteLine(txt);
The following methods are available in the File class:
AppendAllText() – appends text to end of file
Create() – create a file in specified location
Delete() – delete specified file
Exists() – returns true or false
Copy() – copy file to new location
Move() – moves a specified file to a new location.
All methods automatically close the file after performing the operation.
Generics
Generics allow the reuse of code across different types. Swap method, ref means referencing
variable not value:
static void Swap(ref int a, ref int b) {
int temp = a;
a = b;
b = temp;
}
We can overload this method for all the types we want to use it with, however it becomes hard to
manage such a large amount of code. Generics provide a flexible mechanism to define a generic
type.
static void Swap<T>(ref T a, ref T b) {
T temp = a;
a = b;
b = temp;
}
T is the name of our generic type. The method takes two parameters of type T. The brackets are
used to define a generic type. We can use our Swap method with different types now:
static void Swap<T>(ref T a, ref T b) {
T temp = a;
a = b;
b = temp;
}
static void Main(string[] args) {
int a = 4, b = 9;
Swap<int>(ref a, ref b);
//Now b is 4, a is 9

string x = "Hello";
string y = "World";
Swap<string>(ref x, ref y);
//Now x is "World", y is "Hello"
}
When calling a generic method we need to specify the type it will work with by using brackets. If
you do not specify the type the compiler will use the type based on the arguments passed. Multiple
generic parameters can be used with a single method. Example: Func<T, U> takes two different
generic types.
Classes can also be generic. Generic classes are most commonly used with collections of items,
where operations are performed the same way regardless of the type of data being stored. One
type of collection is called a stack. Items are pushed and popped from a stack. A stack is a last in
first out data structure. Example:
class Stack<T> {
int index=0;
T[] innerArray = new T[100];
public void Push(T item) {
innerArray[index++] = item;
}
public T Pop() {
return innerArray[--index];
}
public T Get(int k) { return innerArray[k]; }
}

The generic class stores elements in an array. We can create objects of our generic class:
Stack<int> intStack = new Stack<int>();
Stack<string> strStack = new Stack<string>();
Stack<Person> PersonStack = new Stack<Person>();
We can also use the generic class with custom types, such as the custom defined Person type.
In a generic class we do not need to define the generic type for its methods.

A collection is used to group related objects. Unlike an array it is dynamic and can also group
objects. A collection can grow and shrink to accommodate any number of objects. Collection
classes are organized into namespaces and contain built in methods for processing elements
within the collection.
A collection organizes related data in a computer so that it can be used efficiently. Different types
of collections are suited to different kinds of applications. A collection typically includes methods to
add, remove and count objects. Use the for and foreach statements to iterate through collections.
You must first declare an instance of a collection to use it:
List<int> li = new List<int>();
Generic collections are the preferred type to use as long as every element in the collection is of
the same data type. The .NET framework provides a number of generic collection classes, useful
for storing and manipulating data: List<T>, Dictionary<TKey, TValue>, SortedList<TKey, TValue>,
Stack<T>, Queue<T>, Hashset<T>. To access a generic collection in your code, you will need to
include the statement: using Systems.Collections.Generic;
Non-generic collections can store items that are of type Object. An Object data type can refer to
any data type, and as such runs the risk of unexpected outcomes. These may be slower to access
as well as execute. Systems.Collections namespace includes: ArrayList, SortedList, Stack, Queue,
Hashtable, BitArray. It is recommended to only use generic collections.
A list is similar to an array but the elements can be inserted and removed dynamically. List<T>
Its properties and methods include: Count, Item[int i]-to get or set, Add(T t)-adds to end of list,
RemoveAt(int index), sort().
List<int> li = new List<int>();
li.Add(59);
...
li.RemoveAt(1);

Console.Write("\nList: ");
for (int x = 0; x < li.Count; x++)
Console.Write(li[x] + " ");
li.Sort();
Console.Write("\nSorted: ");
for (int x = 0; x < li.Count; x++)
Console.Write(li[x] + " ");
A sorted list is a collection of key/value pairs that are sorted by key. The C# generic collection
SortedList<K, V> class requires all element key/value pairs to be of the same type K, V. Duplicate
keys are not permitted, all key/value pair is unique. SortedList<K, V> properties include: Count,
Item[K key], Keys-gets a sorted and indexed collection of only keys. Methods include: Add(K key,
V value)-adds an key/value pair, Remove(K key)-removes element.
SortedList<string, int> sl = new SortedList<string, int>();
sl.Add("Solo", 59);
sl.Add("A", 95);
sl.Add("Learn", 72);
sl.Remove("A");
Console.WriteLine("Sorted List: ");
foreach (string s in sl.Keys)
Console.WriteLine(s + ": " + sl[s]); // Learn: 72 Solo: 59
Console.WriteLine("\nCount: " + sl.Count); // 2

A bit array is a collection of bits. A bit can be 1 or 0. They compactly store bits as bools-true or
false. They are used to represent a simple group of Boolean flags or an ordered sequence of
Boolean values.
static void Main(string[] args) {
BitArray ba1 = new BitArray(4);
BitArray ba2 = new BitArray(4);

ba1.SetAll(true);
ba2.SetAll(false);

ba1.Set(2, false);
ba2.Set(3, true);

PrintBarr("ba1", ba1);
PrintBarr("ba2", ba2);
Console.WriteLine();

PrintBarr("ba1 AND ba2", ba1.And(ba2));


PrintBarr(" NOT ba2", ba2.Not());
}

static void PrintBarr(string name, BitArray ba) {


Console.Write(name + " : ");
for (int x = 0; x < ba.Length; x++)
Console.Write(ba.Get(x) + " ");
Console.WriteLine();
}

A stack is a Last In, First Out collection of elements where the last element that goes into the stack
will be the first element that comes out. Pushing is inserting, popping is deleting. These can only
be performed at the top of the stack. Stacks can be used to create undo-redo functionalities,
parsing expressions (infix to postfix/prefix conversion), and much more.
The C# generic collection Stack<T> class requires all elements to be of the same type T.
Stack<int> s = new Stack<int>();

s.Push(59);
...
Console.Write("Stack: ");
foreach (int i in s)
Console.Write(i + " "); // 65 72 59
Console.Write("\nCount: " + s.Count); // 3

Console.Write("\nTop: " + s.Peek()); // 65


Console.Write("\nPop: " + s.Pop()); // 65

Console.Write("\nStack: ");
foreach (int i in s)
Console.Write(i + " "); // 72 59
Console.Write("\nCount: " + s.Count); // 2
A queue is a First In, First Out (FIFO) collection of elements where the first element that goes into
a queue is also the first element that comes out. Inserting an element into a queue is referred to as
Enqueue. Deleting an element from a queue is referred to as Dequeue. Queues are used
whenever we need to manage objects in order starting with the first one in. Such as printing
documents on a printer, call centre systems answering people on hold. C# generic collection
Queue<T>:

Queue<int> q = new Queue<int>();

q.Enqueue(5);
q.Enqueue(10);
q.Enqueue(15);
Console.Write("Queue: ");
foreach (int i in q)
Console.Write(i + " "); // 5 10 15
Console.Write("\nCount: " + q.Count); // 3

Console.Write("\nDequeue: " + q.Dequeue()); // 5

Console.Write("\nQueue: ");
foreach (int i in q)
Console.Write(i + " "); // 10 15
Console.Write("\nCount: " + q.Count); // 2
A dictionary is a collection of unique key/value pairs where a key is used to access the
corresponding value. Dictionaries are used in database indexing, cache implementations and so
on. Duplicate keys are not permitted.

Dictionary<string, int> d = new Dictionary<string, int>();


d.Add("Uno", 1);
d.Add("One", 1);
...
d.Remove("One"); // Remove key-value pair One, 1
...
Console.WriteLine("Dictionary: ");
foreach (string s in d.Keys)
Console.WriteLine(s + ": " + d[s]); // Uno: 1 Deux: 2
Console.WriteLine("\nCount: {0}", d.Count); // 2
A Hash Set is a set of unique values where duplicates are not allowed. They are simply a set of
values and do not have index positions and cannot be ordered. The HashSet<T> class provides
high-performance set operations. HashSets allow fast lookup, addition and removal of items and
can be used to implement either dynamic sets of items or lookup tables that allow finding an item
by its key.

HashSet<int> hs = new HashSet<int>();

hs.Add(5);
...
Console.Write("\nHashSet: ");
foreach (int i in hs)
Console.Write(i + " "); // 5 10 15 20 *elements may be in any
order
Console.Write("\nCount: " + hs.Count); // 4

HashSet<int> hs2 = new HashSet<int>();


hs2.Add(15);
hs2.Add(20);
Console.Write("\n{15, 20} is a subset of {5, 10, 15, 20}: " +
hs2.IsSubsetOf(hs)); // True

You might also like