Short Syllbus Visual C Sharp Programming Notes 5th Semester
Short Syllbus Visual C Sharp Programming Notes 5th Semester
What is C#?
C# is pronounced "C-Sharp".
It is an object-oriented programming language created by Microsoft that runs on the .NET Framework.
C# has roots from the C family, and the language is close to other popular languages
like C++ and Java.
The first version was released in year 2002. The latest version, C# 12, was released in November
2023.
C# is used for:
Mobile applications
Desktop applications
Web applications
Web services
C# Syntax
In the previous chapter, we created a C# file called Program.cs, and we used the following code to
print "Hello World" to the screen:
using System;
namespace HelloWorld
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
}
}
}
Example explained
Line 1: using System means that we can use classes from the System namespace.
Line 2: A blank line. C# ignores white space. However, multiple lines makes the code more readable.
Line 3: namespace is used to organize your code, and it is a container for classes and other
namespaces.
Line 4: The curly braces {} marks the beginning and the end of a block of code.
Line 5: class is a container for data and methods, which brings functionality to your program. Every
line of code that runs in C# must be inside a class. In our example, we named the class Program.
Line 7: Another thing that always appear in a C# program is the Main method. Any code inside its
curly brackets {} will be executed. You don't have to understand the keywords before and after Main.
You will get to know them bit by bit while reading this tutorial.
Line 9: Console is a class of the System namespace, which has a WriteLine() method that is used to
output/print text. In our example, it will output "Hello World!".
If you omit the using System line, you would have to write System.Console.WriteLine() to print/output
text.
Note: Every C# statement ends with a semicolon ;.
Note: C# is case-sensitive; "MyClass" and "myclass" have different meaning.
C# Output
To output values or print text in C#, you can use the WriteLine() method:
Example
Console.WriteLine("Hello World!");
we will only use WriteLine() as it makes it easier to read the output of code.
pg. 1
C# ( Sharp ) Complete Notes
C# Comments
Comments can be used to explain C# code, and to make it more readable. It can also be used to
prevent execution when testing alternative code.
Single-line Comments
Single-line comments start with two forward slashes (//).
Any text between // and the end of the line is ignored by C# (will not be executed).
This example uses a single-line comment before a line of code:
// This is a comment
Console.WriteLine("Hello World!");
C# Multi-line Comments
Multi-line comments start with /* and ends with */.
Any text between /* and */ will be ignored by C#.
This example uses a multi-line comment (a comment block) to explain the code:
Example
/* The code below will print the words Hello World
to the screen, and it is amazing */
Console.WriteLine("Hello World!");
C# Variables
Variables are containers for storing data values.
In C#, there are different types of variables (defined with different keywords), for example:
int - stores integers (whole numbers), without decimals, such as 123 or -123
double - stores floating point numbers, with decimals, such as 19.99 or -19.99
char - stores single characters, such as 'a' or 'B'. Char values are surrounded by single quotes
string - stores text, such as "Hello World". String values are surrounded by double quotes
bool - stores values with two states: true or false
Syntax
type variableName = value;
Example
Create a variable called name of type string and assign it the value "Rashid":
string name = "Rashid";
Console.WriteLine(name);
Example
Create a variable called myNum of type int and assign it the value 15:
int myNum = 15;
Console.WriteLine(myNum);
Example
int myNum;
myNum = 15;
Console.WriteLine(myNum);
Other Types
A demonstration of how to declare variables of other types:
Example
int myNum = 5;
double myDoubleNum = 5.99D;
char myLetter = 'D';
bool myBool = true;
string myText = "Hello";
Constants
If you don't want others (or yourself) to overwrite existing values, you can add the const keyword in
front of the variable type.
pg. 2
C# ( Sharp ) Complete Notes
This will declare the variable as "constant", which means unchangeable and read-only:
Example
const int myNum = 15;
myNum = 20; // error
Note: You cannot declare a constant variable without assigning the value. If you do, an error will
occur: A const field requires a value to be provided.
Display Variables
The WriteLine() method is often used to display variable values to the console window.
To combine both text and a variable, use the + character:
Example
string name = "Rashid";
Console.WriteLine("Hello " + name);
Example
string firstName = "Muhammad ";
string lastName = "Rashid";
string fullName = firstName + lastName;
Console.WriteLine(fullName);
For numeric values, the + character works as a mathematical operator (notice that we use int (integer)
variables here):
Declare Many Variables
To declare more than one variable of the same type, use a comma-separated list:
int x = 5, y = 6, z = 50;
Console.WriteLine(x + y + z);
You can also assign the same value to multiple variables in one line:
Example
int x, y, z;
x = y = z = 50;
Console.WriteLine(x + y + z);
C# Identifiers
All C# variables must be identified with unique names.
These unique names are called identifiers.
Identifiers can be short names (like x and y) or more descriptive names (age, sum, totalVolume).
Note: It is recommended to use descriptive names in order to create understandable and maintainable
code:
Example
// Good
int minutesPerHour = 60;
// OK, but not so easy to understand what m actually is
int m = 60;
The general rules for naming variables are:
Names can contain letters, digits and the underscore character (_)
Names must begin with a letter or underscore
Names should start with a lowercase letter, and cannot contain whitespace
Names are case-sensitive ("myVar" and "myvar" are different variables)
Reserved words (like C# keywords, such as int or double) cannot be used as names
C# Data Types
pg. 3
C# ( Sharp ) Complete Notes
Example
int myNum = 5; // Integer (whole number)
double myDoubleNum = 5.99D; // Floating point number
char myLetter = 'D'; // Character
bool myBool = true; // Boolean
string myText = "Hello"; // String
A data type specifies the size and type of variable values.
It is important to use the correct data type for the corresponding variable; to avoid errors, to save time
and memory, but it will also make your code more maintainable and
readable. The most common data types are:
float 4 bytes Stores fractional numbers. Sufficient for storing 6 to 7 decimal digits
double 8 bytes Stores fractional numbers. Sufficient for storing 15 decimal digits
string 2 bytes per character Stores a sequence of characters, surrounded by double quotes
Numbers
Number types are divided into two groups:
Integer types stores whole numbers, positive or negative (such as 123 or -456), without decimals.
Valid types are int and long. Which type you should use, depends on the numeric value.
Floating point types represents numbers with a fractional part, containing one or more decimals.
Valid types are float and double.
Even though there are many numeric types in C#, the most used for numbers are int (for whole
numbers) and double (for floating point numbers). However, we will describe them all as you continue
to read.
Integer Types
Int
The int data type can store whole numbers from -2147483648 to 2147483647. In general, and in our
tutorial, the int data type is the preferred data type when we create variables with a numeric value.
Example
int myNum = 100000;
Console.WriteLine(myNum);
Long
The long data type can store whole numbers from -9223372036854775808 to 9223372036854775807.
This is used when int is not large enough to store the value. Note that you should end the value with
an "L":
Example
long myNum = 15000000000L;
Console.WriteLine(myNum);
Float Example
float myNum = 5.75F;
Console.WriteLine(myNum);
Use float or double?
The precision of a floating point value indicates how many digits the value can have after the decimal
point. The precision of float is only six or seven decimal digits, while double variables have a precision
of about 15 digits. Therefore it is safer to use double for most calculations.
Scientific Numbers
A floating point number can also be a scientific number with an "e" to indicate the power of 10:
Example
float f1 = 35e3F;
double d1 = 12E4D;
Console.WriteLine(f1);
Console.WriteLine(d1);
Booleans
A boolean data type is declared with the bool keyword and can only take the values true or false:
Example
bool isCSharpFun = true;
bool isFishTasty = false;
Console.WriteLine(isCSharpFun); // Outputs True
Console.WriteLine(isFishTasty); // Outputs False
Characters
The char data type is used to store a single character. The character must be surrounded by single
quotes, like 'A' or 'c':
Example
char myGrade = 'B';
Console.WriteLine(myGrade);
Strings
The string data type is used to store a sequence of characters (text). String values must be
surrounded by double quotes:
Example
string greeting = "Hello World";
Console.WriteLine(greeting);
C# Type Casting
Type casting is when you assign a value of one data type to another type.
In C#, there are two types of casting:
Implicit Casting (automatically) - converting a smaller type to a larger type size
char -> int -> long -> float -> double
Why Conversion?
Many times, there's no need for type conversion. But sometimes you have to. Take a look at the next
chapter, when working with user input, to see an example of this.
Get User Input
You have already learned that Console.WriteLine() is used to output (print) values. Now we will
use Console.ReadLine() to get user input.
In the following example, the user can input his or hers username, which is stored in the
variable userName. Then we print the value of userName:
Example
// Type your username and press enter
Console.WriteLine("Enter username:");
pg. 5
C# ( Sharp ) Complete Notes
// Create a string variable and get user input from the keyboard and store it in the variable
string userName = Console.ReadLine();
// Print the value of the variable (userName), which will display the input value
Console.WriteLine("Username is: " + userName);
User Input and Numbers
The Console.ReadLine() method returns a string. Therefore, you cannot get information from another
data type, such as int. The following program will cause an error:
Note: If you enter wrong input (e.g. text in a numerical input), you will get an exception/error
message (like System.FormatException: 'Input string was not in a correct format.').
Operators
Operators are used to perform operations on variables and values.
In the example below, we use the + operator to add together two values:
int x = 100 + 50;
Although the + operator is often used to add together two values, like in the example above, it can also
be used to add together a variable and a value, or a variable and another variable:
Example
int sum1 = 100 + 50; // 150 (100 + 50)
int sum2 = sum1 + 250; // 400 (150 + 250)
int sum3 = sum2 + sum2; // 800 (400 + 400)
Operator Name Description Example
Assignment Operators
Assignment operators are used to assign values to variables.
In the example below, we use the assignment operator (=) to assign the value 10 to a variable
called x:
Example
int x = 10;
The addition assignment operator (+=) adds a value to a variable:
Example
int x = 10;
x += 5;
Comparison Operators
Comparison operators are used to compare two values (or variables). This is important in
programming, because it helps us to find answers and make decisions.
The return value of a comparison is either True or False. These values are known as Boolean values,
and you will learn more about them in the Booleans and If..Else chapter.
In the following example, we use the greater than operator (>) to find out if 5 is greater than 3:
Example
int x = 5;
int y = 3;
Console.WriteLine(x > y); // returns True because 5 is greater than 3
pg. 6
C# ( Sharp ) Complete Notes
== Equal to x == y
!= Not equal x != y
Logical Operators
As with comparison operators, you can also test for True or False values with logical operators.
Logical operators are used to determine the logic between variables or values:
Logical operators are used to determine the logic between variables or values:
Operator Name Description Example
&& Logical and Returns True if both statements are true x < 5 && x < 10
! Logical not Reverse the result, returns False if the result is true !(x < 5 && x < 10)
You will learn more about comparison and logical operators in the Booleans and If...Else chapters.
Math.Max(x,y)
The Math.Max(x,y) method can be used to find the highest value of x and y:
Example
Math.Max(5, 10);
C# Booleans
Very often, in programming, you will need a data type that can only have one of two values, like:
YES / NO
ON / OFF
TRUE / FALSE
For this, C# has a bool data type, which can take the values true or false.
Boolean Values
A boolean type is declared with the bool keyword and can only take the values true or false:
However, it is more common to return boolean values from boolean expressions, for conditional testing (see below).
Boolean Expression
A Boolean expression returns a boolean value: True or False, by comparing values/variables.
This is useful to build logic, and find answers.
For example, you can use a comparison operator, such as the greater than (>) operator to find out if
an expression (or a variable) is true:
C# Conditions
C# Conditions and If Statements
C# supports the usual logical conditions from mathematics:
Less than: a < b
Less than or equal to: a <= b
Greater than: a > b
Greater than or equal to: a >= b
Equal to a == b
Not Equal to: a != b
You can use these conditions to perform different actions for different decisions.
C# has the following conditional statements:
Use if to specify a block of code to be executed, if a specified condition is true
Use else to specify a block of code to be executed, if the same condition is false
Use else if to specify a new condition to test, if the first condition is false
Use switch to specify many alternative blocks of code to be executed
The if Statement
Use the if statement to specify a block of C# code to be executed if a condition is True.
Syntax
if (condition)
{
// block of code to be executed if the condition is True
}
Note that if is in lowercase letters. Uppercase letters (If or IF) will generate an error.
In the example below, we test two values to find out if 20 is greater than 18. If the condition is True,
print some text:
Example
if (20 > 18)
{
Console.WriteLine("20 is greater than 18");
}
We can also test variables:
Example
int x = 20;
int y = 18;
if (x > y)
{
Console.WriteLine("x is greater than y");
}
Example explained
In the example above we use two variables, x and y, to test whether x is greater than y (using
the > operator). As x is 20, and y is 18, and we know that 20 is greater than 18, we print to the screen
that "x is greater than y".
The else Statement
Use the else statement to specify a block of code to be executed if the condition is False.
Syntax
if (condition)
{
// block of code to be executed if the condition is True
}
else
{
// block of code to be executed if the condition is False
}
Example
int time = 20;
pg. 8
C# ( Sharp ) Complete Notes
Use the else if statement to specify a new condition if the first condition is False.
Syntax
if (condition1)
{
// block of code to be executed if condition1 is True
}
else if (condition2)
{
// block of code to be executed if the condition1 is false and condition2 is True
}
else
{
// block of code to be executed if the condition1 is false and condition2 is False
}
Example
int time = 22;
if (time < 10)
{
Console.WriteLine("Good morning.");
}
else if (time < 20)
{
Console.WriteLine("Good day.");
}
else
{
Console.WriteLine("Good evening.");
}
// Outputs "Good evening."
Example explained
In the example above, time (22) is greater than 10, so the first condition is False. The next
condition, in the else if statement, is also False, so we move on to the else condition
since condition1 and condition2 is both False - and print to the screen "Good evening".
However, if the time was 14, our program would print "Good day.
pg. 9
C# ( Sharp ) Complete Notes
There is also a short-hand if else, which is known as the ternary operator because it consists of three
operands. It can be used to replace multiple lines of code with a single line. It is often used to replace
simple if else statements:
Syntax
variable = (condition) ? expressionTrue : expressionFalse;
Instead of writing:
Example
int time = 20;
if (time < 18)
{
Console.WriteLine("Good day.");
}
else
{
Console.WriteLine("Good evening.");
}
You can simply write:
Example
int time = 20;
string result = (time < 18) ? "Good day." : "Good evening.";
Console.WriteLine(result);
C# Switch Statements
Use the switch statement to select one of many code blocks to be executed.
Syntax
switch(expression)
{
case x:
// code block
break;
case y:
// code block
break;
default:
// code block
break;
}
Example
int day = 4;
switch (day)
{
case 1:
Console.WriteLine("Monday");
break;
case 2:
Console.WriteLine("Tuesday");
break;
case 3:
Console.WriteLine("Wednesday");
break;
case 4:
Console.WriteLine("Thursday");
break;
pg. 10
C# ( Sharp ) Complete Notes
case 5:
Console.WriteLine("Friday");
break;
case 6:
Console.WriteLine("Saturday");
break;
case 7:
Console.WriteLine("Sunday");
break;
}
// Outputs "Thursday" (day 4)
Example
int day = 4;
switch (day)
{
case 6:
Console.WriteLine("Today is Saturday.");
break;
case 7:
Console.WriteLine("Today is Sunday.");
break;
default:
Console.WriteLine("Looking forward to the Weekend.");
break;
}
// Outputs "Looking forward to the Weekend."
Loops
Loops can execute a block of code as long as a specified condition is reached.
Loops are handy because they save time, reduce errors, and they make code more readable.
C# While Loop
The while loop loops through a block of code as long as a specified condition is True:
Syntax
while (condition)
{
// code block to be executed
}
In the example below, the code in the loop will run, over and over again, as long as a variable (i) is
less than 5:
Example
int i = 0;
while (i < 5)
{
Console.WriteLine(i);
i++;
}
pg. 11
C# ( Sharp ) Complete Notes
Note: Do not forget to increase the variable used in the condition, otherwise the loop will never end!
Do not forget to increase the variable used in the condition, otherwise the loop will never end!
C# For Loop
When you know exactly how many times you want to loop through a block of code, use the for loop
instead of a while loop:
Syntax
for (statement 1; statement 2; statement 3)
{
// code block to be executed
}
Statement 1 is executed (one time) before the execution of the code block.
Statement 2 defines the condition for executing the code block.
Statement 3 is executed (every time) after the code block has been executed.
The example below will print the numbers 0 to 4:
Example
for (int i = 0; i < 5; i++)
{
Console.WriteLine(i);
}
Example explained
Statement 1 sets a variable before the loop starts (int i = 0).
Statement 2 defines the condition for the loop to run (i must be less than 5). If the condition is true,
the loop will start over again, if it is false, the loop will end.
Statement 3 increases a value (i++) each time the code block in the loop has been executed.
Another Example
This example will only print even values between 0 and 10:
Example
for (int i = 0; i <= 10; i = i + 2)
{
Console.WriteLine(i);
}
Nested Loops
It is also possible to place a loop inside another loop. This is called a nested loop.
The "inner loop" will be executed one time for each iteration of the "outer loop":
Example
// Outer loop
for (int i = 1; i <= 2; ++i)
pg. 12
C# ( Sharp ) Complete Notes
{
Console.WriteLine("Outer: " + i); // Executes 2 times
// Inner loop
for (int j = 1; j <= 3; j++)
{
Console.WriteLine(" Inner: " + j); // Executes 6 times (2 * 3)
}
}
Syntax
foreach (type variableName in arrayName)
{
// code block to be executed
}
The following example outputs all elements in the cars array, using a foreach loop:
Example
string[] cars = {"Volvo", "BMW", "Ford", "Mazda"};
foreach (string i in cars)
{
Console.WriteLine(i);
}
C# Break
You have already seen the break statement used in an earlier chapter of this tutorial. It was used to
"jump out" of a switch statement.
The break statement can also be used to jump out of a loop.
This example jumps out of the loop when i is equal to 4:
Example
for (int i = 0; i < 10; i++)
{
if (i == 4)
{
break;
}
Console.WriteLine(i);
}
C# Continue
The continue statement breaks one iteration (in the loop), if a specified condition occurs, and continues with the next
iteration in the loop.
Continue Example
int i = 0;
while (i < 10)
{
if (i == 4)
{
i++;
continue;
}
Console.WriteLine(i);
i++;
}
C# Arrays
Create an Array
Arrays are used to store multiple values in a single variable, instead of declaring separate variables for each value.
To declare an array, define the variable type with square brackets:
string[] cars;
We have now declared a variable that holds an array of strings.
To insert values to it, we can use an array literal - place the values in a comma-separated list, inside curly braces:
string[] cars = {"Volvo", "BMW", "Ford", "Mazda"};
To create an array of integers, you could write:
int[] myNum = {10, 20, 30, 40};
Access the Elements of an Array
You access an array element by referring to the index number.
This statement accesses the value of the first element in cars:
Example
string[] cars = {"Volvo", "BMW", "Ford", "Mazda"};
Console.WriteLine(cars[0]);
// Outputs Volvo
Note: Array indexes start with 0: [0] is the first element. [1] is the second element, etc.
Change an Array Element
To change the value of a specific element, refer to the index number:
Example
cars[0] = "Opel";
Example
string[] cars = {"Volvo", "BMW", "Ford", "Mazda"};
cars[0] = "Opel";
Console.WriteLine(cars[0]);
// Now outputs Opel instead of Volvo
Array Length
To find out how many elements an array has, use the Length property:
Example
string[] cars = {"Volvo", "BMW", "Ford", "Mazda"};
Console.WriteLine(cars.Length);
// Outputs 4
Other Ways to Create an Array
pg. 14
C# ( Sharp ) Complete Notes
If you are familiar with C#, you might have seen arrays created with the new keyword, and perhaps you have seen arrays with a
specified size as well. In C#, there are different ways to create an array:
// Create an array of four elements, and add values later
string[] cars = new string[4];
It is up to you which option you choose. In our tutorial, we will often use the last option, as it is faster and easier to read.
However, you should note that if you declare an array and initialize it later, you have to use the new keyword:
You can loop through the array elements with the for loop, and use the Length property to specify how
many times the loop should run.
Example
string[] cars = {"Volvo", "BMW", "Ford", "Mazda"};
for (int i = 0; i < cars.Length; i++)
{
Console.WriteLine(cars[i]);
}
C# Sort Arrays
Sort an Array
There are many array methods available, for example Sort(), which sorts an array alphabetically or in
an ascending order:
Example
// Sort a string
string[] cars = {"Volvo", "BMW", "Ford", "Mazda"};
Array.Sort(cars);
foreach (string i in cars)
{
Console.WriteLine(i);
}
// Sort an int
int[] myNumbers = {5, 1, 8, 9};
Array.Sort(myNumbers);
foreach (int i in myNumbers)
{
Console.WriteLine(i);
}
System.Linq Namespace
pg. 15
C# ( Sharp ) Complete Notes
Other useful array methods, such as Min, Max, and Sum, can be found in the System.Linq namespace:
Example
using System;
using System.Linq;
namespace MyApplication
{
class Program
{
static void Main(string[] args)
{
int[] myNumbers = {5, 1, 8, 9};
Console.WriteLine(myNumbers.Max()); // returns the largest value
Console.WriteLine(myNumbers.Min()); // returns the smallest value
Console.WriteLine(myNumbers.Sum()); // returns the sum of elements
}
}
}
C# Multidimensional Arrays
Multidimensional Arrays
you learned about arrays, which is also known as single dimension arrays. These are great, and
something you will use a lot while programming in C#. However, if you want to store data as a tabular
form, like a table with rows and columns, you need to get familiar with multidimensional arrays.
A multidimensional array is basically an array of arrays.
Arrays can have any number of dimensions. The most common are two-dimensional arrays (2D).
Two-Dimensional Arrays
To create a 2D array, add each array within its own set of curly braces, and insert a comma (,) inside
the square brackets:
Example
int[,] numbers = { {1, 4, 2}, {3, 6, 8} };
Good to know: The single comma [,] specifies that the array is two-dimensional. A three-dimensional
array would have two commas: int[,,].
numbers is now an array with two arrays as its elements. The first array element contains three
elements: 1, 4 and 2, while the second array element contains 3, 6 and 8. To visualize it, think of the
array as a table with rows and columns:
Access Elements of a 2D Array
To access an element of a two-dimensional array, you must specify two indexes: one for the array, and
one for the element inside that array. Or better yet, with the table visualization in mind; one for the
row and one for the column (see example below).
This statement accesses the value of the element in the first row (0) and third column (2) of
the numbers array:
Example
int[,] numbers = { {1, 4, 2}, {3, 6, 8} };
Console.WriteLine(numbers[0, 2]); // Outputs 2
Remember that: Array indexes start with 0: [0] is the first element. [1] is the second element, etc.
Change Elements of a 2D Array
You can also change the value of an element.
C# Methods
A method is a block of code which only runs when it is called.
You can pass data, known as parameters, into a method.
Methods are used to perform certain actions, and they are also known as functions.
Why use methods? To reuse code: define the code once, and use it many times.
Example
Create a method inside the Program class:
pg. 16
C# ( Sharp ) Complete Notes
class Program
{
static void MyMethod()
{
// code to be executed
}
}
Example Explained
MyMethod() is the name of the method
static means that the method belongs to the Program class and not an object of the Program
class. You will learn more about objects and how to access methods through objects later in this
tutorial.
void means that this method does not have a return value. You will learn more about return
values later in this chapter
Note: In C#, it is good practice to start with an uppercase letter when naming methods, as it makes
the code easier to read.
Call a Method
To call (execute) a method, write the method's name followed by two parentheses () and a semicolon;
In the following example, MyMethod() is used to print a text (the action), when it is called:
Example
Inside Main(), call the myMethod() method:
static void MyMethod()
{
Console.WriteLine("I just got executed!");
}
C# Method Parameters
// Rashid Refsnes
// Saad Refsnes
// Hassan Refsnes
pg. 17
C# ( Sharp ) Complete Notes
When a parameter is passed to the method, it is called an argument. So, from the example
above: fname is a parameter, while Liam, Jenny and Anja are arguments.
Note that when you are working with multiple parameters, the method call must have the same
number of arguments as there are parameters, and the arguments must be passed in the same order.
Example
static void MyMethod(string country = "Norway")
{
Console.WriteLine(country);
}
C# Return Values
Return Values
we used the void keyword in all examples, which indicates that the method should not return a value.
If you want the method to return a value, you can use a primitive data type (such as int or double)
instead of void, and use the return keyword inside the method:
Example
static int MyMethod(int x)
{
return 5 + x;
}
// Outputs 8 (5 + 3)
C# Named Arguments
Named Arguments
It is also possible to send arguments with the key: value syntax.
That way, the order of the arguments does not matter:
Example
static void MyMethod(string child1, string child2, string child3)
{
Console.WriteLine("The youngest child is: " + child3);
}
C# Method Overloading
Method Overloading
With method overloading, multiple methods can have the same name with different parameters:
Example
int MyMethod(int x)
float MyMethod(float x)
double MyMethod(double x, double y)
Consider the following example, which have two methods that add numbers of different type:
# OOP
C# - What is OOP?
Procedural programming is about writing procedures or methods that perform operations on the data,
while object-oriented programming is about creating objects that contain both data and methods.
Tip: The "Don't Repeat Yourself" (DRY) principle is about reducing the repetition of code. You should
extract out the codes that are common for the application, and place them at a single place and reuse
them instead of repeating it.
Classes and objects are the two main aspects of object-oriented programming.
Look at the following illustration to see the difference between class and objects:
pg. 19
C# ( Sharp ) Complete Notes
Another Example
When the individual objects are created, they inherit all the variables and methods from the class.
Create a Class
To create a class, use the class keyword:
When a variable is declared directly in a class, it is often referred to as a field (or attribute).
It is not required, but it is a good practice to start with an uppercase first letter when naming classes.
Also, it is common that the name of the C# file and the class matches, as it makes our code organized.
However it is not required (like in Java).
Create an Object
An object is created from a class. We have already created the class named Car, so now we can use
this to create objects.
To create an object of Car, specify the class name, followed by the object name, and use the
keyword new:
Example
Create an object called "myObj" and use it to print the value of color:
class Car
{
string color = "red";
Multiple Objects
You can create multiple objects of one class:
Example
Create two objects of Car:
class Car
pg. 20
C# ( Sharp ) Complete Notes
{
string color = "red";
static void Main(string[] args)
{
Car myObj1 = new Car();
Car myObj2 = new Car();
Console.WriteLine(myObj1.color);
Console.WriteLine(myObj2.color);
}
}
Using Multiple Classes
You can also create an object of a class and access it in another class. This is often used for better
organization of classes (one class has all the fields and methods, while the other class holds
the Main() method (code to be executed)).
prog2.cs
prog.cs
prog2.cs
class Car
{
public string color = "red";
}
prog.cs
class Program
{
static void Main(string[] args)
{
Car myObj = new Car();
Console.WriteLine(myObj.color);
}
}
Did you notice the public keyword? It is called an access modifier, which specifies that
the color variable/field of Car is accessible for other classes as well, such as Program.
C# Class Members
Class Members
Fields and methods inside classes are often referred to as "Class Members":
Example
Create a Car class with three class members: two fields and one method.
// The class
class MyClass
{
// Class members
string color = "red"; // field
int maxSpeed = 200; // field
public void fullThrottle() // method
{
Console.WriteLine("The car is going as fast as it can!");
}
}
Fields
In the previous chapter, you learned that variables inside a class are called fields, and that you can
access them by creating an object of the class, and by using the dot syntax (.).
The following example will create an object of the Car class, with the name myObj. Then we print the
value of the fields color and maxSpeed:
pg. 21
C# ( Sharp ) Complete Notes
Example
class Car
{
string color = "red";
int maxSpeed = 200;
Console.WriteLine(Ford.model);
Console.WriteLine(Opel.model);
}
}
Object Methods
You learned from the C# Methods chapter that methods are used to perform certain actions.
Methods normally belong to a class, and they define how an object of a class behaves.
Just like with fields, you can access methods with the dot syntax. However, note that the method must
be public. And remember that we use the name of the method followed by two parentheses () and a
semicolon ; to call (execute) the method:
Example
class Car
pg. 22
C# ( Sharp ) Complete Notes
{
string color; // field
int maxSpeed; // field
public void fullThrottle() // method
{
Console.WriteLine("The car is going as fast as it can!");
}
C# Constructors
Constructors
A constructor is a special method that is used to initialize objects. The advantage of a constructor, is
that it is called when an object of a class is created. It can be used to set initial values for fields:
Example
Create a constructor:
pg. 23
C# ( Sharp ) Complete Notes
Note that the constructor name must match the class name, and it cannot have a return
type (like void or int).
Also note that the constructor is called when the object is created.
All classes have constructors by default: if you do not create a class constructor yourself, C# creates
one for you. However, then you are not able to set initial values for fields.
Constructor Parameters
The following example adds a string modelName parameter to the constructor. Inside the constructor
we set model to modelName (model=modelName). When we call the constructor, we pass a parameter to
the constructor ("Mustang"), which will set the value of model to "Mustang":
Example
class Car
{
public string model;
Tip: Just like other methods, constructors can be overloaded by using different numbers of
parameters.
Console.WriteLine(Ford.model);
Console.WriteLine(Opel.model);
}
}
With constructor:
prog.cs
class Program
{
static void Main(string[] args)
{
Car Ford = new Car("Mustang", "Red", 1969);
Car Opel = new Car("Astra", "White", 2005);
Console.WriteLine(Ford.model);
Console.WriteLine(Opel.model);
}
}
C# Access Modifiers
Access Modifiers
By now, you are quite familiar with the public keyword that appears in many of our examples:
pg. 25
C# ( Sharp ) Complete Notes
The public keyword is an access modifier, which is used to set the access level/visibility for classes,
fields, methods and properties.
protected The code is accessible within the same class, or in a class that is inherited from that class. You will learn
more about inheritance in a later chapter
internal The code is only accessible within its own assembly, but not from another assembly. You will learn more
about this in a later chapter
There's also two combinations: protected internal and private protected.
For now, lets focus on public and private modifiers.
Private Modifier
If you declare a field with a private access modifier, it can only be accessed within the same class:
Example
class Car
{
private string model = "Mustang";
class Program
{
static void Main(string[] args)
{
Car myObj = new Car();
Console.WriteLine(myObj.model);
}
}
Public Modifier
If you declare a field with a public access modifier, it is accessible for all classes:
pg. 26
C# ( Sharp ) Complete Notes
Example
class Car
{
public string model = "Mustang";
}
class Program
{
static void Main(string[] args)
{
Car myObj = new Car();
Console.WriteLine(myObj.model);
}
}
pg. 27
C# ( Sharp ) Complete Notes
Example explained
The Name property is associated with the name field. It is a good practice to use the same name for both
the property and the private field, but with an uppercase first letter.
The get method returns the value of the variable name.
The set method assigns a value to the name variable. The value keyword represents the value we
assign to the property.
If you don't fully understand it, take a look at the example below.
Now we can use the Name property to access and update the private field of the Person class:
Example
class Person
{
private string name; // field
public string Name // property
{
get { return name; }
set { name = value; }
}
}
class Program
{
static void Main(string[] args)
{
Person myObj = new Person();
myObj.Name = "Rashid";
Console.WriteLine(myObj.Name);
}
}
The output will be:
Rashid
class Program
{
static void Main(string[] args)
{
Person myObj = new Person();
myObj.Name = "Rashid";
Console.WriteLine(myObj.Name);
}
}
The output will be:
Rashid
Why Encapsulation?
pg. 28
C# ( Sharp ) Complete Notes
Better control of class members (reduce the possibility of yourself (or others) to mess up the
code)
Fields can be made read-only (if you only use the get method), or write-only (if you only use
the set method)
Flexible: the programmer can change one part of the code without affecting other parts
Increased security of data
C# Inheritance
class Program
{
static void Main(string[] args)
{
// Create a myCar object
Car myCar = new Car();
// Call the honk() method (From the Vehicle class) on the myCar object
myCar.honk();
// Display the value of the brand field (from the Vehicle class) and the value of the
modelName from the Car class
Console.WriteLine(myCar.brand + " " + myCar.modelName);
}
}
{
...
}
C# Polymorphism
Remember from the Inheritance chapter that we use the : symbol to inherit from a class.
Now we can create Pig and Dog objects and call the animalSound() method on both of them:
Example
class Animal // Base class (parent)
{
public void animalSound()
{
Console.WriteLine("The animal makes a sound");
}
}
pg. 30
C# ( Sharp ) Complete Notes
class Program
{
static void Main(string[] args)
{
Animal myAnimal = new Animal(); // Create a Animal object
Animal myPig = new Pig(); // Create a Pig object
Animal myDog = new Dog(); // Create a Dog object
myAnimal.animalSound();
myPig.animalSound();
myDog.animalSound();
}
}
pg. 31
C# ( Sharp ) Complete Notes
{
public override void animalSound()
{
Console.WriteLine("The dog says: bow wow");
}
}
class Program
{
static void Main(string[] args)
{
Animal myAnimal = new Animal(); // Create a Animal object
Animal myPig = new Pig(); // Create a Pig object
Animal myDog = new Dog(); // Create a Dog object
myAnimal.animalSound();
myPig.animalSound();
myDog.animalSound();
}
}
The output will be:
The animal makes a sound
The pig says: wee wee
The dog says: bow wow
C# Abstraction
Abstract method: can only be used in an abstract class, and it does not have a body. The
body is provided by the derived class (inherited from).
An abstract class can have both abstract and regular methods:
abstract class Animal
{
public abstract void animalSound();
public void sleep()
{
Console.WriteLine("Zzz");
}
}
From the example above, it is not possible to create an object of the Animal class:
Animal myObj = new Animal(); // Will generate an error (Cannot create an instance of the
abstract class or interface 'Animal')
To access the abstract class, it must be inherited from another class. Let's convert the Animal class we
used in the Polymorphism chapter to an abstract class.
pg. 32
C# ( Sharp ) Complete Notes
Remember from the Inheritance chapter that we use the : symbol to inherit from a class, and that we
use the override keyword to override the base class method.
Example
// Abstract class
abstract class Animal
{
// Abstract method (does not have a body)
public abstract void animalSound();
// Regular method
public void sleep()
{
Console.WriteLine("Zzz");
}
}
class Program
{
static void Main(string[] args)
{
Pig myPig = new Pig(); // Create a Pig object
myPig.animalSound(); // Call the abstract method
myPig.sleep(); // Call the regular method
}
}
Why And When To Use Abstract Classes and Methods?
To achieve security - hide certain details and only show the important details of an object.
Note: Abstraction can also be achieved with Interfaces
C# Interface
Interfaces
Another way to achieve abstraction in C#, is with interfaces.
An interface is a completely "abstract class", which can only contain abstract methods and
properties (with empty bodies):
Example
// interface
interface Animal
{
void animalSound(); // interface method (does not have a body)
void run(); // interface method (does not have a body)
}
It is considered good practice to start with the letter "I" at the beginning of an interface, as it makes it
easier for yourself and others to remember that it is an interface and not a class.
By default, members of an interface are abstract and public.
Note: Interfaces can contain properties and methods, but not fields.
pg. 33
C# ( Sharp ) Complete Notes
To access the interface methods, the interface must be "implemented" (kinda like inherited) by another
class. To implement an interface, use the : symbol (just like with inheritance). The body of the
interface method is provided by the "implement" class. Note that you do not have to use
the override keyword when implementing an interface:
Example
// Interface
interface IAnimal
{
void animalSound(); // interface method (does not have a body)
}
class Program
{
static void Main(string[] args)
{
Pig myPig = new Pig(); // Create a Pig object
myPig.animalSound();
}
}
Notes on Interfaces:
Like abstract classes, interfaces cannot be used to create objects (in the example above, it is
not possible to create an "IAnimal" object in the Program class)
Interface methods do not have a body - the body is provided by the "implement" class
On implementation of an interface, you must override all of its methods
Interfaces can contain properties and methods, but not fields/variables
Interface members are by default abstract and public
An interface cannot contain a constructor (as it cannot be used to create objects)
Why And When To Use Interfaces?
1) To achieve security - hide certain details and only show the important details of an object
(interface).
2) C# does not support "multiple inheritance" (a class can only inherit from one base class). However,
it can be achieved with interfaces, because the class can implement multiple interfaces. Note: To
implement multiple interfaces, separate them with a comma (see example below).
Multiple Interfaces
interface ISecondInterface
{
void myOtherMethod(); // interface method
}
pg. 34
C# ( Sharp ) Complete Notes
C# Enums
An enum is a special "class" that represents a group of constants (unchangeable/read-only variables).
To create an enum, use the enum keyword (instead of class or interface), and separate the enum items
with a comma:
Example
enum Level
{
Low,
Medium,
High
}
You can access enum items with the dot syntax:
Level myVar = Level.Medium;
Console.WriteLine(myVar);
pg. 35
C# ( Sharp ) Complete Notes
Enum Values
By default, the first item of an enum has the value 0. The second has the value 1, and so on.
To get the integer value from an item, you must explicitly convert the item to an int:
Example
enum Months
{
January, // 0
February, // 1
March, // 2
April, // 3
May, // 4
June, // 5
July // 6
}
High
}
C# Exceptions - Try..Catch
C# Exceptions
When executing C# code, different errors can occur: coding errors made by the programmer, errors
due to wrong input, or other unforeseeable things.
When an error occurs, C# will normally stop and generate an error message. The technical term for
this is: C# will throw an exception (throw an error).
Syntax
try
{
// Block of code to try
}
catch (Exception e)
{
// Block of code to handle errors
}
pg. 37
C# ( Sharp ) Complete Notes
In the following example, we use the variable inside the catch block (e) together with the built-
in Message property, which outputs a message that describes the exception:
Example
try
{
int[] myNumbers = {1, 2, 3};
Console.WriteLine(myNumbers[10]);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
The output will be:
Index was outside the bounds of the array.
Example
try
{
int[] myNumbers = {1, 2, 3};
Console.WriteLine(myNumbers[10]);
}
catch (Exception e)
{
Console.WriteLine("Something went wrong.");
}
The output will be:
Something went wrong.
Finally
The finally statement lets you execute code, after try...catch, regardless of the result:
Example
try
{
int[] myNumbers = {1, 2, 3};
Console.WriteLine(myNumbers[10]);
}
catch (Exception e)
{
Console.WriteLine("Something went wrong.");
}
finally
{
Console.WriteLine("The 'try catch' is finished.");
}
The output will be:
Something went wrong.
The 'try catch' is finished.
pg. 38
C# ( Sharp ) Complete Notes
Introduction to Event
Events are a way for an object to broadcast (to all interested components in the system) that something has
happened. Any other component can subscribe to the event, and be notified when an event is raised.
You've probably used events in some of your programming. Many graphical systems have an event model to report
user interaction. These events would report mouse movement, button presses and similar interactions. That's one of
the most common, but certainly not the only scenario where events are used.
Declaration of the Event
Syntax
For the declaration of the Event in the class, firstly, the event type of the delegate must be declared.
We can invoke the Event only from within the class where we declared the Event.
Event-driven programming (EDP) is a programming paradigm where external events determine the flow of program
execution. These events come in different shapes: user actions (e.g., button clicks, keyboard inputs), system events
(like a finished file download), messages from other programs, sensor outputs, etc.
pg. 39
C# ( Sharp ) Complete Notes
The basic idea of message handlers is that the class receives messages of some sort and dispatches them, calling
one of a set of specified methods depending on the message received. If no specific method exists for a particular
message, there is a default handler.
User Interface
graphical user interface (GUI) framework that enables developers to create desktop applications for the Windows
operating system.
Graphics Device Interface
The Graphics Device Interface (GDI) is a Microsoft Windows application programming interface and core operating
system component responsible for representing graphical objects and transmitting them to output devices such
as monitors and printers.
GDI is responsible for tasks such as drawing lines and curves, rendering fonts and handling palettes. It is not directly
responsible for drawing windows, menus, etc.; that task is reserved for the user subsystem, which resides in
user32.dll and is built atop GDI. GDI is similar to Macintosh's QuickDraw and GNOME/GTK's GDK/Xlib.
window management
Window management deals with the management of Design Windows in the Workspace. Window management allows
for closing, resizing, and arranging of multiple simultaneously opened Design Windows within the Workspace.
Specifically, the tasks for window management are: Window Closing.
Input Devices
an input device is a piece of equipment used to provide data and control signals to an information processing system,
such as a computer or information appliance. Examples of input devices include keyboards, computer mice, scanners,
cameras, joysticks, and microphones. Duration: 35 seconds.
Resources in C#
Resources is a very useful namespace that allows you to create and store culture-specific resources used in an
application (for example, you can have Spanish and English resources). Resources allows you to place culture-
specific items inside satellite files, rather than directly in your main application.
Menu Resources
A menu resource is a collection of information that defines the appearance and function of an application menu. A
menu is a special input tool that lets a user select commands and open submenus from a list of menu items
Dialog control in C#
A dialog box in C# is a type of window, which is used to enable common communication or dialog between a
computer and its user. A dialog box is most often used to provide the user with the means for specifying how to
implement a command or to respond to a question. Windows.
Window control in C#
pg. 40
C# ( Sharp ) Complete Notes
Controls can be added to the Windows forms C# via the Toolbox in Visual Studio. Controls such as labels,
checkboxes, radio buttons, etc
1) Windows form controls are implemented by extensible managed classes. Office controls are unmanaged.
2) Windows form controls have no concept of their location in relation to the containing workbook or document. You
can use this Controls collection to enumerate through all the controls
Common control in C#
A control is a child window an application uses in conjunction with another window to. perform simple input and output
(I/O) tasks. Controls are most often used within dialog. boxes, but they can also be used in other windows.
Scroll bars
Input fields
Combo boxes and drop-down lists
Check boxes
Radio buttons
Group frames
Text controls
Buttons and hyperlinks
Tree views
Visual style
The first thing to consider when styling controls is whether the controls will be used in themed UI. Controls in standard
UI are non-themed UI and must follow normal Windows Desktop style, meaning that they are not re-templated and
should appear in their default control appearance.
Standard (utility) dialogs: not themed. Don't re-template. Use basic control style defaults.
Tool windows, document editors, design surfaces and themed dialogs: Use specialized themed appearance
using the color service.
Scroll bars
Scroll bars should follow common interaction patterns for Windows scroll bars unless they're augmented with content
information, like in the code editor.
Input fields
For typical interaction behavior, follow the Windows Desktop guidelines for text boxes.
Visual style
Input fields shouldn't be styled in utility dialogs. Use the basic style intrinsic to the control.
Themed input fields should only be used in themed dialogs and tool windows.
Specialized interactions
Read-only fields will have a gray (disabled) background but default (active) foreground.
pg. 41
C# ( Sharp ) Complete Notes
Required fields should have <Required> as watermarks within them. You should not change the color of the
background except in rare situations.
Error validation: See Notifications and Progress for Visual Studio
Input fields should be sized to fit the content, not to fit the width of the window in which they are shown, nor to
arbitrarily match the length of a long field, like a path. Length might be an indication to the user of limitations
as to how many characters are allowed in the field.
Incorrect input field length: it's unlikely that the name will be this long.
Correct input field length: the input field is a reasonable width for the expected content.
For typical interaction behavior, follow the Windows Desktop guidelines for drop-down lists and combo boxes.
Visual style
In utility dialogs, don't re-template the control. Use the basic style intrinsic to the control.
In themed UI, combo boxes and drop-downs follow the standard theming for the controls.
Layout
Combo boxes and drop-downs should be sized to fit the content, not to fit the width of the window in which they are
shown, nor to arbitrarily match the length of a long field, like a path.
Incorrect: the drop-down width is too long for the content that will be displayed.
Correct: the drop-down is sized to allow for translation growth, but not unnecessarily long.
pg. 42
C# ( Sharp ) Complete Notes
Check boxes
For typical interaction behavior, follow the Windows Desktop guidelines for check boxes.
Visual style
In utility dialogs, don't re-template the control. Use the basic style intrinsic to the control.
In themed UI, check boxes follow the standard theming for the controls.
Specialized interactions
Interaction with a check box must never pop a dialog or navigate to another area.
Align check boxes with the baseline of the first line of text.
Correct: the check box is aligned with the first line of the text.
Radio buttons
For typical interaction behavior, follow the Windows Desktop guidelines for radio buttons.
Visual style
In utility dialogs, do not style radio buttons. Use the basic style intrinsic to the control.
Specialized interactions
It's not necessary to use a group frame to enclose radio choices, unless you need to maintain group distinction in a
tight layout.
Group frames
For typical interaction behavior, follow the Windows Desktop guidelines for group frames.
Visual style
In utility dialogs, don't style group frames. Use the basic style intrinsic to the control.
pg. 43
C# ( Sharp ) Complete Notes
Layout
It's not necessary to use a group frame to enclose radio choices, unless you need to maintain group distinction
in a tight layout.
Never use a group frame for a single control.
It's sometimes acceptable to use a horizontal rule instead of a group frame container.
Text controls
A static text field presents read-only information and cannot be selected by the user. Avoid using it for any text the
user might want to copy to the clipboard. However, read-only static text can change to reflect a change in state. In the
example below, the Output Name static text under the Information group changes to reflect any changes made to the
Root Namespace text box above it.
Static text can be on its own in a dialog without any containment when there is no grouping conflict. Decide if the
extra lines of a box are really necessary. An example is the display of a directory path under a section created by a
group line, as shown below:
In a dialog where other grouped areas exist and containment of the information would help readability, and when a
section can be hidden or shown (as in the Properties window description pane) or you want to be consistent with
similar UI, place the static text inside a box. This group box should be a single rule and colored with
the ButtonShadow:
pg. 44
C# ( Sharp ) Complete Notes
This allows the user to select the text inside the field but not edit it. These text boxes are bordered by the usual 3-D
chisel with a ButtonShadow fill.
A text box can become active (editable) when a user alters an associated control, such as checking/unchecking a check
box or selecting/deselecting a radio button. For example, in the Tools > Options page shown below, the Home
Page text box becomes active when the Use Default check box is unchecked.
pg. 45
C# ( Sharp ) Complete Notes
Labels for text boxes, list boxes, and frames in unthemed dialogs start with a verb, have an initial capital on the
first word only, and end with a colon.
Text controls in themed dialogs follow Windows desktop UX guidelines and do not take end punctuation, with
the exception of question marks in Help links.
Labels for check boxes and option buttons start with a verb, an initial capital on the first word only, and have no
ending punctuation.
Labels for buttons, menus, menu items, and tabs have initial capitals on each word (title case).
Label terminology should be consistent with similar labels in other dialogs.
If possible, have a writer/editor write or approve the text before it goes to the developer for implementation.
All controls should have labels except in special circumstances in which tabbing is sufficient. Use helper text
when appropriate.
Helper text
Included in dialogs to help the user understand the dialog's purpose or to indicate which action to take. Helper text
should be used only when needed to avoid cluttering simple dialogs. The two variations of helper text are dialog and
watermark.
Follow common locations for helper text and be selective in introducing new areas. Common scenarios for helper text
are:
Helper text in dialogs, to give additional direction about how to interact with a complex dialog.
Watermark text in empty tool windows or dialogs, to explain why no content is visible.
A description pane, like at the bottom of the Properties window.
Watermark text in an empty editor, to explain what action the user should take to get started.
A user experience designer may help determine when helper text is appropriate. The designer can define where helper
text appears as well as its general content. User assistance can write/edit the actual text.
Watermarks
Dialogs benefit from slightly different watermark guidelines. Because a dialog can appear busy with many UI elements
(labels, hint text, buttons and other container controls with text), particularly when those appear in black, watermarks
stand out better in dark gray (VSColor: ButtonShadow). Typically a watermark appears inside a control like a list box
with a white background (VSColor: Window).
The text appears in dark gray (VSColor: ButtonShadow). However, if the watermark appears on a medium gray
or other-colored (VSColor: ButtonFace) background and there is concern about its readability, go with black
text (VSColor: WindowText).
Watermarks can be centered or flush left. Apply standard design rules when making alignment decisions. The
watermark cannot be selected on the background.
pg. 46
C# ( Sharp ) Complete Notes
Dynamic text can be used one of two ways in a dialog or modeless UI: either as a dynamic label or as dynamic content.
Dynamic label: a common use of dynamic text is in descriptive panels that offer more information for the
selected item, such as in a dialog which contains a list of elements and properties for those elements displayed
in a grid to the right. The label for the property grid may be dynamic so that when an item is selected on the
left, the grid to the right shows information for that specific item.
Dynamic text: can be useful in instances where you need to display specific information and not general
information in this way, but care should be taken to not overuse.
If you want users to have the ability to copy the info, dynamic text should be in a read-only text field.
Buttons and link controls (hyperlinks) should follow basic Windows Desktop guidance on hyperlinks for usage,
wording, sizing, and spacing.
Traditionally, buttons have been used for actions and hyperlinks have been reserved for navigation. Buttons may be
used in all cases, but the role of links has been expanded in Visual Studio so that buttons and links are more
interchangeable in some conditions.
Primary commands
Displaying windows used to gather input or making choices, even if they are secondary commands
Destructive or irreversible actions
pg. 47
C# ( Sharp ) Complete Notes
Avoid command buttons in tool windows, or if you need more than two words for the label. Links can have longer
labels.
Examples
pg. 48
C# ( Sharp ) Complete Notes
Links used for secondary commands where buttons would attract too much attention
Common buttons
Text
Visual style
Standard (unthemed)
Most buttons in Visual Studio will appear in utility dialogs and should not be styled. They should reflect the standard
appearance of buttons as dictated by the operating system.
Themed
In some instances, buttons may be used within styled UI and these buttons must be styled appropriately.
See Dialogs for information on themed controls.
Special buttons
Browse... buttons
[Browse...] buttons are used in grids, dialogs, and tool windows and other modeless UI elements. They display a
picker that assists the user in filling a value into a control. There are two variations of this button, long and short.
pg. 49
C# ( Sharp ) Complete Notes
If there is more than one long [Browse...] button in a dialog, like when several fields allow for browsing. Use the
short [...] button for each to avoid the confusing access keys created by this situation
(&Browse and B&rowse in the same dialog).
In a tight dialog, or when there is no reasonable place to put the long button.
If the button will appear in a grid control.
Don't use an access key. To access it using the keyboard, the user must tab from the adjacent control. Ensure
that the tab order is such that any browse button falls immediately after the field that it will fill. Never use an
underscore below the first period.
Set the Microsoft Active Accessibility (MSAA) Name property to Browse... (including the ellipsis) so that screen
readers will read it as "Browse" and not "dot-dot-dot" or "period-period-period." For managed controls, this
means setting the AccessibleName property.
Never use an ellipsis [...] button for anything except a browse action. For example, if you need a [New...] button
but don't have enough room for the text, then the dialog needs to be redesigned.
Graphical buttons
Some buttons should always use a graphical image and never include text to conserve space and avoid localization
problems. These are often used in field pickers and other sortable lists.
Note
Users have to tab to these buttons (there are no access keys), so place them in a sensible order. Map
the name property of the button to the action that it takes so that screen readers correctly interpret the button action.
Expand table
Function Button
Add
Remove
Add All
Remove All
Move Up
Move Down
Delete
Sizing for graphical buttons is the same as for the short version of the [Browse...] button (26x23 pixels):
Appearance of a graphical image on button, with and without transparent color showing
Hyperlinks
Hyperlinks are well suited to navigation-based actions, like opening a Help topic, modal dialog, or wizard. If a
hyperlink is used for a command, it should always display a visible and noticeable change to the UI. In general, actions
that commit to an action (like Save, Cancel, and Delete) are better communicated using a button.
Writing style
Follow the Windows Desktop guidance for user interface text. Don't use "Learn more about," "Tell me more about," or
"Get help with this" phrasing. Instead, phrase Help link text in terms of the primary question answered by the Help
content. For example, "How do I add a server to the Server Explorer?"
pg. 51
C# ( Sharp ) Complete Notes
Visual style
Hyperlinks should always use The VSColor Service. If a hyperlink is not styled correctly, it flashes red when active
or shows a different color after being visited.
Don't include underlines at the control resting state unless the link is a sentence fragment within a full sentence,
like in a watermark.
Underlines shouldn't appear on hover. Instead, the feedback to the user that the link is active is a slight color
change and the appropriate link cursor.
Tree views
Tree views provide a way to organize complex lists into parent-child groups. A user can expand or collapse parent
groups to reveal or hide underlying child items. Each item within a tree view can be selected to provide further action.
Expanders
Tree view controls should conform to the expander design used by Windows and Visual Studio. Each node uses an
expander control to reveal or hide underlying items. Using an expander control provides consistency for users who
might encounter different tree views within Windows and Visual Studio.
Selection
When a node is selected within the tree view, the highlight should expand to the full width of the tree view control.
This helps users clearly identify which item they have selected. Selection colors should reflect the current Visual Studio
theme.
Correct: highlight of the selected node fits the entire width of the tree view control.
pg. 52
C# ( Sharp ) Complete Notes
Incorrect: highlight of the selected node doesn't fit the entire width of the tree view control.
Icons
Icons should only be used in tree view controls if they assist in visually identifying differences between items. In
general, icons should be used only in heterogeneous lists in which the Icons carry information to differentiate the
types of elements. In a homogeneous list using icons can frequently be seen as noise and should be avoided. In that
case the group icon (parent) can convey the type of items within it. The exception to this rule would be if the icon is
dynamic and is used to indicate state.
Scroll bars
Scroll bars should always be hidden if the content fits within the tree view control. It is acceptable for scrollbars to be
hidden, or semi-transparent in a scrollable window and appear when the window containing the tree view has focus, or
upon hover of the tree view itself.
Both vertical and horizontal scroll bars are displayed because the contents have exceeded the limits of the tree view
control.
Context menus
A tree view node can reveal submenu options in a context menu. Typically, this occurs when a user has right-clicked an
item or pressed the Menu key on a Windows keyboard with the item selected. It's important that the node gains focus
and is selected. This helps the user identify which item the submenu belongs to.
The item that has generate the context menu gains focus to notify the user which item has been selected.
Keyboard
The tree view should provide the ability to select items and expand/collapse nodes using the keyboard. This ensures
that navigation meets our accessibility requirements.
A trid control is a complex control that contains a tree view within a grid. Expanding, collapsing, and navigating the
tree should respect the same keyboard commands as a tree view, with the following additions:
Right Arrow: Expand a node. After the node is expanded, it should continue navigating to the nearest column
on the right. Navigation should stop at the end of the row.
Tab: Navigates to the nearest cell on the right. At the end of the row, navigation continues to the next row.
Shift + Tab: Navigates to the nearest cell on the left. At the beginning of the row, navigation continues to the
rightmost cell in the previous row.
Internal functions are typically intended to be called only from within the DLL where they are defined. Although a DLL
can export data, its data is generally used only by its functions. However, there is nothing to prevent another module
from reading or writing that address.
DLLs provide a way to modularize applications so that their functionality can be updated and reused more easily. DLLs
also help reduce memory overhead when several applications use the same functionality at the same time, because
although each application receives its own copy of the DLL data, the applications share the DLL code.
Threads in C#
Multi-threading is the most useful feature of C# which allows concurrent programming of two or more parts of the
program for maximizing the utilization of the CPU. Each part of a program is called Thread. So, in other words,
threads are lightweight processes within a process.
Synchronization in C#
Ensures that only one thread is accessing the shared resource at any given point in time, preventing other threads
from doing the same at the same time. Thread Synchronization in C# is a mechanism that is used to restrict multiple
threads from accessing a shared resource at the same time.
Network programming
is the act of using computer code to write programs or processes that can communicate with other programs or
processes across a network. Programmers use various programming languages, code libraries, and protocols to do
the work.
The .NET framework provides two namespaces, System.Net and System.Net.Sockets for network programming. The
classes and methods of these namespaces help us to write programs, which can communicate across the network.
pg. 54
C# ( Sharp ) Complete Notes
The communication can be either connection-oriented or connectionless. They can also be either stream-oriented or
data-gram-based. The most widely used protocol TCP is used for stream-based communication and UDP is used for
data-grams-based applications.
DNS class
The System.net namespace provides this class, which can be used to create and send queries to obtain information
about the host server from the Internet Domain Name Service (DNS). Remember that in order to access DNS, the
machine executing the query must be connected to a network. If the query is executed on a machine, that does not
have access to a domain name server, a System.Net.SocketException is thrown. All the members of this class are
static in nature. The important methods of this class are given below.
public static IPHostEntry GetHostByAddress(string address)
C#
Copy
Where address should be in a dotted-quad format like "202.87.40.193". This method returns an IPHostEntry instance
containing the host information. If the DNS server is not available, the method returns a SocketException.
public static string GetHostName()
C#
Copy
This method returns the DNS hostname of the local machine.
In my machine Dns.GetHostName() returns Rajesh which is the DNS name of my machine.
public static IPHostEntry Resolve(string hostname)
C#
Copy
This method resolves a DNS hostname or IP address to an IPHostEntry instance. The hostname should be in a
dotted-quad format like 127.0.01 or www.microsoft.com.
IPHostEntry class
This is a container class for Internet host address information. This class makes no thread safety guarantees. The
following are the important members of this class.
AddressList property
Gives an IPAddress array containing IP addresses that resolve to the hostname.
Aliases property
Gives a string array containing a DNS name that resolves to the IP addresses in the AddressList property.
Assembly in C#
private assembly deployment
A private assembly is an assembly that is deployed with an application and is available for the exclusive use of that
application.
Introduction:
Assembly is an important concept in C#. It is a collection of code files that are compiled into an executable or a Dynamic
Link Library (DLL). Depending on their location and intended use, assemblies can be divided into many categories. We
will examine the various assembly types in C# in this article.
Private Assemblies:
An Assembly that is solely used by one application is referred to as a Private Assembly. It is typically found in the directory
for the application or a subdirectory of the directory for the programme. Private Assemblies are not intended to be
shared with other applications. They are used to store application-specific code and resources.
Private Assemblies are created when an application is compiled. When an application is compiled, all the code files and
resources that are used by the application are compiled into a single assembly.The application's directory or a
subdirectory of the application's directory will thereafter contain this assembly.
Private Assemblies are simple to deploy and use. They don't need any extra installation or setting. They are automatically
loaded by the .NET runtime when the application starts.
pg. 55
C# ( Sharp ) Complete Notes
Shared Assemblies:
An assembly that is used by several programmes is referred to as a shared assembly. It is typically found in the Global
Assembly Cache (GAC) or a common directory. Multiple applications are supposed to share a shared assembly. They
are used to store resources and code that are shared by various applications.
Shared Assemblies are created using the strong name tool (sn.exe). A digital signature for the assembly is applied using
the strong name tool. The digital signature guarantees that the assembly is genuine and unaltered.
The Global Assembly Cache (GAC) houses shared assemblies. Shared assemblies are kept in the GAC, which serves as
a central repository. The GAC location is in the Windows directory (C:\Windows\assembly). Shared assemblies are
registered with the GAC using the gacutil.exe tool.
Shared assemblies require special configuration and installation. They cannot be simply copied to the application's
directory. They need to be registered with the GAC using the gacutil.exe tool.
Satellite Assemblies:
An assembly used to store regional resources is referred to as a Satellite Assembly. It is typically found in a subdirectory
of the directory for the application or a subdirectory of the directory for the Shared Assembly. Localized resources like
strings, pictures, and audio files are kept in satellite assemblies.
Satellite Assemblies are created using the resgen.exe tool. The resgen.exe tool is used to create a resource
file (.resx) from a text file. The resource file is then compiled into a satellite assembly using the al.exe tool.
ADVERTISEMENT
Satellite Assemblies are named using a specific naming convention. The naming convention for satellite assemblies is as
follows:
1. <AssemblyName>.resources.dll
The <AssemblyName> part of the name is the name of the main assembly that the satellite assembly is associated
with. The.NET runtime automatically loads satellite assemblies when the application first launches. The .NET runtime
automatically selects the appropriate satellite assembly based on the user's culture settings.
Dynamic Link Libraries (DLLs):
A Dynamic Link Library (DLL) is a type of assembly that contains code that can be used by multiple applications. Similar
to shared assemblies, DLLs are created with the intention of being used by numerous applications. DLLs, however, differ
from shared assemblies in that they do not have a distinctive name.
DLLs are kept in the directory of the application or a subdirectory of the directory of the application. They can be used
by multiple applications by simply copying the DLL to the application's directory.
DLLs are created using the same tools that are used to create shared assemblies. However, DLLs do not require a strong
name. They can be signed with a digital signature, but this is optional.
Configuration in C#
In C#, appsettings. json is a configuration file used to store application settings in a structured format. It is commonly
used in ASP.NET Core applications, but it can also be utilized in other types of C# application
Configuration file in C#
A configuration file (web. config) is used to manage various settings that define a website. The settings are stored in
XML files that are separate from your application code. In this way you can configure settings independently from your
code.
pg. 56
C# ( Sharp ) Complete Notes
You can access run-time configuration settings from within an ASP.NET application or a .NET client application. Each
configuration section has its own object type, which in the case of C# requires a cast when calling the methods of
the WebConfigurationManager class. For more information about the object type that is associated with a
configuration section, see the section handler in the Element Information table in the reference topics under ASP.NET
Configuration Settings.
The code example in this topic uses the non-static method of obtaining configuration data. This allows you to obtain
configuration information from any application. If you are going to obtain configuration information from the
application in which your code resides, use the static GetSection methods, which process faster. For more information,
see the Working with Local and Remote Configuration Settings section in ASP.NET Configuration API Overview.
A software development kit (SDK) is a set of software tools and programs provided by hardware and software vendors
that developers can use to build applications for specific platforms. SDKs help developers easily integrate their apps
with a vendor's services.
SDKs include documentation, application programming interfaces (APIs), code samples, libraries and processes, as
well as guides that developers can use and integrate into their apps. Developers can use SDKs to build and maintain
applications without having to write everything from scratch.
More specifically, SDKs include the following components:
Libraries are a collection of reusable and packaged pieces of code that perform specific functions.
APIs are predefined pieces of code that let developers perform common programming tasks on the platform.
Integrated development environments (IDEs) are visual editors that help with the design and layout of
graphical elements, such as text boxes and buttons. These are common in mobile software app development
toolkits. For instance, Apple's IDE, Xcode, contains a suite of software development tools to help developers build
software for macOS, iOS, iPadOS, watchOS and tvOS. There are numerous IDE options for Android.
Testing tools and compilers include debugging tools to help developers identify coding errors at various stages
of application development.
Documentation encompasses the instructions and tutorials vendors provide to help developers as they go
through the development stages.
Benefits of SDKs
Different types of SDKs can be used for a variety of programming languages and mobile applications. By assembling
the needed set of tools in one location, SDKs simplify standard processes and add more functionality to applications.
The following are the key benefits of using SDKs:
Time saving. SDKs let developers easily and quickly build the standard components of their apps and add
functionality to them. SDKs are usually all-in-one products and don't need to be integrated with other components,
which can slow down the development process.
Easier integration. Developers use SDKs for simple functions, such as logging in, location services and mobile
payments. However, some SDKs help developers build more complex app features, such as augmented
reality and virtual reality, and add new features. SDKs reduce the complexity of integrations by simplifying
standard processes, such as creating authorization signatures and interpreting SMS messages in native
languages or platforms.
Metadata
Metadata is binary information describing your program that is stored either in a common language runtime portable
executable (PE) file or in memory. When you compile your code into a PE file, metadata is inserted into one portion of
the file, and your code is converted to Microsoft intermediate language (MSIL) and inserted into another portion of
the file. Every type and member that is defined and referenced in a module or assembly is described within metadata.
When code is executed, the runtime loads metadata into memory and references it to discover information about your
code's classes, members, inheritance, and so on.
Metadata describes every type and member defined in your code in a language-neutral manner. Metadata stores the
following information:
Description of the assembly.
pg. 57
C# ( Sharp ) Complete Notes
Reflection in C#
Reflection objects are used for obtaining type information at runtime. The classes that give access to the metadata of
a running program are in the System.Reflection namespace.
The System.Reflection namespace contains classes that allow you to obtain information about the application and to
dynamically add types, values, and objects to the application.
Applications of Reflection
Reflection has the following applications −
It allows view attribute information at runtime.
It allows examining various types in an assembly and instantiate these types.
It allows late binding to methods and properties
It allows creating new types at runtime and then performs some tasks using those types.
pg. 58
C# ( Sharp ) Complete Notes
Early Binding
A binding is called an early binding, compiler time binding or static type binding when the target method is found
during compile time (the code that will call the method is also created during compile time). If the required method
doesn’t exist, an error is issued during compilation.
Whether there is an extra step to find the method during call time is irrelevant. That means, the binding is still
considered early independently of if the method is virtual or not.
For example, the next code block uses early binding to call the RandomMethod method of the
object EarlyBindingSample, and then the method NotExistingMethod that doesn’t exist. Since the second method
doesn’t exists, the compiler throws an error:
Late Binding
Late binding or runtime binding in C# is achieved with reflection. Late bound means the target method is looked up at
run time. Often the textual name of the method is used to look it up. If the method isn’t there, the program will crash
or go into some exception handling scheme during run time.
For example, the code bellow uses reflection to locate and execute two methods, one existing and one not. Since the
object returned by the activator is converted to ILateBoundSample, the compiler knows that the
method NotExistingMethod doesn’t exist, so this is causing a compiler error. On the other hand, using the same
interface the compiler assumes that a method named RandomMethod exists in the load type and it compiles properly.
This assumption is usually correct, and the approach saves us from many awkward runtime late binding errors, but
there is no Holy Grail – we can never be sure the implementation of the method RandomMethod actually exists in the
loaded type
Directory in C#
The Directory class in C# and. NET provides functionality to work with folders. This article covers how to read a
folder's properties, get the size and number of files of a folder, create a folder, create a subfolder, iterate through all
files in a folder, move a folder, and delete a folder.
C# Files
pg. 59
C# ( Sharp ) Complete Notes
Replace() Replaces the contents of a file with the contents of another file
WriteAllText() Creates a new file and writes the contents to it. If the file already exists, it will be overwritten.
C# SerializableAttribute
To serialize the object, you need to apply SerializableAttribute attribute to the type. If you don't
apply SerializableAttribute attribute to the type, SerializationException exception is thrown at runtime.
C# Serialization example
Let's see the simple example of serialization in C# where we are serializing the object of Student class. Here, we are
going to use BinaryFormatter.Serialize(stream, reference) method to serialize the object.
Memory Management
Memory management is the process of allocating and de-allocating memory resources during a program’s execution to
ensure efficient utilization of available memory. It plays a critical role in preventing memory-related issues like memory
leaks, buffer overflows, and access violations.
In managed programming languages like C#, memory management is handled by the runtime environment, relieving
developers of many low-level memory management tasks. Common Language Runtime (CLR) is responsible for
managing memory, and it employs a sophisticated garbage collector to automatically release memory that is no longer
in use.
Garbage Collector
The garbage collector (GC) serves as an automatic memory manager. The garbage collector manages the allocation
and release of memory for an application. Therefore, developers working with managed code don't have to write code
to perform memory management tasks. Automatic memory management can eliminate common problems such as
forgetting to free an object and causing a memory leak or attempting to access freed memory for an object that's
already been freed.
This article describes the core concepts of garbage collection.
Benefits
The garbage collector provides the following benefits:
Frees developers from having to manually release memory.
Allocates objects on the managed heap efficiently.
Reclaims objects that are no longer being used, clears their memory, and keeps the memory available for future
allocations. Managed objects automatically get clean content to start with, so their constructors don't have to
initialize every data field.
Provides memory safety by making sure that an object can't use for itself the memory allocated for another
object.
Asynchronous Delegates
pg. 60
C# ( Sharp ) Complete Notes
Delegates are also used in threading specially for the Callback operation. It enables to call a synchronous method in
an asynchronous manner. It is basically used in cases like to report information back after the completion of operation,
a thread needs a pointer to be able to execute the Callback, etc.
Application Domain
Application domains provide an isolation boundary for security, reliability, and versioning, and for unloading
assemblies. Application domains are typically created by runtime hosts, which are responsible for bootstrapping the
common language runtime before an application is run.
The benefits of isolating applications
Historically, process boundaries have been used to isolate applications running on the same computer. Each
application is loaded into a separate process, which isolates the application from other applications running on the
same computer.
The applications are isolated because memory addresses are process-relative; a memory pointer passed from one
process to another cannot be used in any meaningful way in the target process. In addition, you cannot make direct
calls between two processes. Instead, you must use proxies, which provide a level of indirection.
Managed code must be passed through a verification process before it can be run (unless the administrator has
granted permission to skip the verification). The verification process determines whether the code can attempt to
access invalid memory addresses or perform some other action that could cause the process in which it is running to
fail to operate properly. Code that passes the verification test is said to be type-safe. The ability to verify code as type-
safe enables the common language runtime to provide as great a level of isolation as the process boundary, at a much
lower performance cost.
Application domains provide a more secure and versatile unit of processing that the common language runtime can
use to provide isolation between applications. You can run several application domains in a single process with the
same level of isolation that would exist in separate processes, but without incurring the additional overhead of making
cross-process calls or switching between processes. The ability to run multiple applications within a single process
dramatically increases server scalability.
Isolating applications is also important for application security. For example, you can run controls from several Web
applications in a single browser process in such a way that the controls cannot access each other's data and resources.
The isolation provided by application domains has the following benefits:
Faults in one application cannot affect other applications. Because type-safe code cannot cause memory faults,
using application domains ensures that code running in one domain cannot affect other applications in the
process.
Individual applications can be stopped without stopping the entire process. Using application domains enables
you to unload the code running in a single application.
Code running in one application cannot directly access code or resources from another application. The
common language runtime enforces this isolation by preventing direct calls between objects in different
application domains. Objects that pass between domains are either copied or accessed by proxy. If the object is
copied, the call to the object is local. That is, both the caller and the object being referenced are in the same
application domain. Application domains and assemblies
The runtime host determines whether to load assemblies as domain-neutral when it loads the runtime into a process.
For managed applications, apply the LoaderOptimizationAttribute attribute to the entry-point method for the process,
and specify a value from the associated LoaderOptimization enumeration. For unmanaged applications that host the
common language runtime, specify the appropriate flag when you call the CorBindToRuntimeEx Function method.
There are three options for loading domain-neutral assemblies:
LoaderOptimization.SingleDomain loads no assemblies as domain-neutral, except Mscorlib, which is always
loaded domain-neutral. This setting is called single domain because it is commonly used when the host is
running only a single application in the process.
A domain-neutral assembly can be JIT-compiled more than once. For example, when the security grant sets of two
application domains are different, they cannot share the same JIT-compiled code. However, each copy of the JIT-
compiled assembly can be shared with other application domains that have the same grant set.
When you decide whether to load assemblies as domain-neutral, you must make a tradeoff between reducing memory
use and other performance factors.
pg. 61
C# ( Sharp ) Complete Notes
Access to static data and methods is slower for domain-neutral assemblies because of the need to isolate
assemblies. Each application domain that accesses the assembly must have a separate copy of the static data, to
prevent references to objects in static fields from crossing domain boundaries. As a result, the runtime contains
additional logic to direct a caller to the appropriate copy of the static data or method. This extra logic slows
down the call.
All the dependencies of an assembly must be located and loaded when the assembly is loaded domain-neutral,
because a dependency that cannot be loaded domain-neutral prevents the assembly from being loaded
domain-neutral.
Marshal by Value: When you marshal an object by value, a copy of the object is passed to the target location. Any
changes made to the copy do not affect the original object. In C#, you can use the Serializable attribute to mark a
class as serializable, allowing it to be marshaled by value.
Marshal by Reference: When you marshal an object by reference, you pass a reference to the object, rather than a
copy of the object itself. This means that changes made to the object at the target location affect the original object. In
C#, you can use remoting or other inter-process communication mechanisms to achieve marshal by reference
pg. 62
C# ( Sharp ) Complete Notes
In Visual C# (or C# in general), authorization and authentication are typically implemented using various .NET
frameworks and libraries. Here's a basic overview of each:
1. Authentication: Authentication is the process of verifying the identity of a user. In C#, you can implement
authentication using ASP.NET Identity, which provides features for managing user accounts, including password
hashing, two-factor authentication, and external authentication providers (such as Google, Facebook, etc.).
2. Authorization: Authorization is the process of determining whether an authenticated user has the necessary
permissions to access a resource. In C#, you can use ASP.NET Core's authorization middleware to implement role-
based or policy-based authorization.
Configuring security
Configuring security in Visual C# typically involves securing your application at various levels, including the application
level, web server level, and network level. Here's a general overview of how you can configure security in a Visual C#
application:
1. Code Access Security (CAS): Code Access Security allows you to control what your code is allowed to do, based on
where it comes from and who wrote it. However, CAS has been deprecated since .NET Framework 4 and is no longer
recommended for new development.
2. Code Group Security: Code groups are used in CAS to group assemblies with similar permissions requirements. Each
code group is associated with a permission set that determines the permissions granted to assemblies in that code
group.
1. dentity: An identity represents the user or entity (such as a service or application) that is trying to access a resource. In
.NET, the System.Security.Principal.IIdentity interface represents an identity. An identity typically contains
information such as the name of the user and any roles or claims associated with the user.
2. Principal: A principal represents the security context under which code is running, including the identity of the user
and any roles or claims associated with the user. In .NET, the System.Security.Principal.IPrincipal
interface represents a principal. The Thread.CurrentPrincipal property is commonly used to get or set the
current principal for the current thread.
Principals and identities are fundamental to implementing authentication and authorization in .NET applications,
allowing you to control access to resources based on the identity and roles of the user.
Data Reader in Visual C#
In Visual C#, a DataReader is used to efficiently read a forward-only stream of rows from a data source, such as a
database (e.g., SQL Server, MySQL). It's part of the ADO.NET framework and is particularly useful when you need to
read large sets of data quickly and efficiently.
Here's a basic example of using a DataSet to retrieve and manipulate data from a SQL Server database:
In this example, replace YourServer, YourDatabase, YourTable, and TableName with your actual server,
database, and table names. The SqlDataAdapter is used to fill the DataSet with data from the database. You can
then access the data in the DataSet through its Tables collection, which contains DataTable objects. Each
DataTable represents a table of data and can be iterated over to access its rows and columns.
pg. 63
C# ( Sharp ) Complete Notes
Interacting with XML in Visual C# involves reading, writing, and manipulating XML data using the classes provided in
the .NET Framework's System.Xml namespace. XML (eXtensible Markup Language) is a widely used format for
storing and exchanging data in a structured way. Here's a brief overview of how you can work with XML in Visual C#
Tracing to Event Logs
Using tracing within an application allows its activities to be logged and reviewed later to assist with identifying and
resolving bugs. Messages can be sent to various locations, including Windows event logs that can be examined using
the Event Viewer.
EventLogTraceListener
When you are developing applications it is useful to include logging functionality. If you encounter bugs, or when test
users report issues, the logs can be reviewed and may help you to track down those problems. A simple way of
providing logging is via the Debug and Trace classes. These classes allow you to output messages to trace listeners,
which control how those messages are outputted. For example, information can easily be sent to the Visual Studio
output window or to a text file.
The Boolean Switch and Trace Switch classes are used for controlling the tracing output of your application. They
allow you to dynamically enable or disable tracing based on the value of a switch. Here's how you can use them:
Boolean Switch: This switch is either on or off (true or false). It's useful when you only need to enable or disable
tracing without different levels of verbosity.
TraceSwitch: This switch allows you to specify different levels of tracing (e.g., Off, Error, Warning, Info, Verbose).
You can set the Level property to control the verbosity of the tracing output
In C#, you can use the Debug class from the System.Diagnostics namespace to print debugging information. The
Debug class provides methods for writing debug messages to the output window in development environments like
Visual Studio. Here's a basic example:
In this example, Debug.WriteLine is used to print debug messages to the output window. You can use string
interpolation ($"") to include variable values in the messages. Debug.Assert can be used to assert a condition and
print a message if the condition is false. When running the application in Visual Studio, you can view the debug output
in the "Output" window (View -> Output)
Application instrumentation gives you the ability to perform runtime diagnosis of enterprise application state, which is
critical to mission success.
To help with instrumentation and logging, .NET ships with tracing types in the System.Diagnostics namespace. Using
these types, you have the ability to log information to multiple output streams for diagnosis of application runtime
behavior. Information produced by instrumentation and tracing types enable you to examine the runtime state of an
application and fix problems that would be otherwise expensive and painful to solve.
The Trace class allows you to perform logging in a production system, giving you the ability to analyze application
behavior during run time.
Two of the primary types in the System.Diagnostics namespace for application instrumentation are
the Debug and Trace classes. Both classes have the same functionality but different use cases. Use the Debug class
during development and use the Trace class in production applications.
pg. 64
C# ( Sharp ) Complete Notes
The types for debugging and tracing, which come with the .NET Framework library, are convenient because they
provide reuse and extendable functionality. You don't have to create your own logging library and you can build
custom instrumentation types.
When tracing, you can control output with switches. A BooleanSwitch turns tracing on and off. TraceSwitch lets you
trace at different levels. Alternatively, you can create a custom switch to define identifiers, granularity, and logic that
meets the requirements of a given application.
Trace output is sent to another type called a TraceListener. .NET ships with trace listeners for writing to the console,
event log, or text files. You can also define your own trace listener for output to the stream of your choice.
Instrumentation is a critical component of enterprise application development, enabling you to build maintainable,
reliable, and robust systems. Through Debug and Trace classes, switches, and trace listeners, you have the ability to
instrument your application in an easy and flexible manner.
Configuration
The Debug and Trace classes have the same functionality, but Microsoft designed them for different purposes. You
use the Debug class for development purposes and it relies on DEBUG being defined. Use the Trace class for
production purposes. It relies on TRACE being defined.
By default, Visual Studio .NET (VS.NET) defines both DEBUG and TRACE for Debug (development) configurations
and only TRACE for Release (production) configurations. To view your project configurations in VS.NET, right-click on
the project, select Properties, select Configuration Properties, select the Build option, and view the Conditional
Compilation Constants property. When compiling C# applications from the command-line, compilation configuration
options are specified with the /define: or /d: option, as follows:
csc.exe /d:TRACE MyApp.cs
Basic Tracing
For this article we'll use the Trace class to show how to use .NET types for instrumentation of production systems.
While I wrote the examples in this article as Console applications for simplicity, you can use this information for
instrumenting any kind of .NET application, including ASP.NET, remoting, Web services, and Windows Forms.
The Trace class has several members that control output, which you can see in Listing 1.
When your tracing needs are simple, that is, you only need to turn tracing on or off, a Boolean switch is a good choice.
The first line in Listing 1 adds a TraceListener to the Listeners collection. TraceListeners are discussed in the
Trace Listeners section of this article. They let you specify where the output of write statements will go.
The WriteLine and Write methods write output with and without a newline, respectively.
The WriteLineIf and WriteIf methods write output if a condition evaluates to true. The category parameter enables
you to prefix the output with a tag string, which is useful for filtering log entries.
Boolean Switches
A BooleanSwitch will allow you to produce trace output only when the switch is true. When all tracing is turned on,
the output can quickly use a lot of resources if saving output to file or some other persistent store. If your application is
small or you don't hold log information longer than immediate diagnosis, a BooleanSwitch will work fine. Listing
2 shows how to use a BooleanSwitch.
The code in Listing 2 is very simple?if boolSwitch.Enabled evaluates to true, then the string parameter to
the WriteLineIf method is sent to output.
Trace Switches
The problem with a BooleanSwitch approach to instrumentation is that it is all-or-nothing. Most of the time, you need
more granularity in your approach. For example, perhaps during normal operations you only want to know about error
conditions. However, to diagnose a problem, you need the ability to trace more information for a short period of time.
The level of information you need at any given time could vary depending on what you need to know. Here you'll find
value using the TraceSwitch.
When your code declares the TraceSwitch variable, it is instantiated with the MyTraceSwitch parameter, which
corresponds to the same entry in the switches element of the configuration file in Listing 5. This configuration file
sets MyTraceSwitch to 4, which turns on tracing for Verbose and every level below it. As implied, the trace level
setting in the configuration file turns on tracing for the level it is set at in addition to all lower levels.
The TraceSwitch class has Boolean properties that correspond to each trace level. Listing 4 demonstrates how to
use the traceSwitch variable as the first parameter to WriteLineIf to determine if a specific trace level is set before
logging output.
Custom Switches
pg. 65
C# ( Sharp ) Complete Notes
Switches that ship with .NET will work fine for most cases. However, there are times when you may want to implement
your own custom switches. Perhaps you want to migrate another system where you have a different logging strategy
that worked and you want to mimic that strategy in .NET. What if the all-inclusive logic of the TraceSwitch didn't quite
meet your needs?
Existing switches don't provide the output control you need? With reusable types in the .NET Framework Class Library
you can create your own custom switch.
I'll demonstrate how to create a custom switch. I designed my example to give you ideas of how you could implement
your own custom switch to achieve the granularity and logic handling appropriate for your needs.
The custom switch in Listing 6, FlagSwitch, creates new switch categories: None, Enter, Exit, Info, and Exception.
As opposed to the TraceSwitch where higher switch levels are all inclusive of lower levels, the FlagSwitch lets you
turn categories on and off at will.
Advertisement
The FlagLevel enum is decorated with the [Flags] attribute, allowing you to use it in bitwise operations. You can
explicitly set each element with a hex value to ensure their values don't overlap.
Notice how my example exposes each switch setting as a property. The get accessors use the SwitchSetting of the
base class, Switch, and use a bit-wise AND operation to check if the bit representing that condition is set.
The Switch class takes care of reading configuration file settings and ensures that the SwitchSetting property is set
accordingly. The implementation also ensures that in all properties, except for None, the None bit is turned off, since
this would represent an illogical condition.
Trace Configuration
The configuration files in previous examples showed how to add a single switch to an application. You can do more
with configuration files including add additional switches and remove switches. The following snippet shows these
additional switch configuration capabilitie
The configuration file adds three switches, which you can use in different parts of an application to give you more
control over where you want to view debug output. The remove element essentially un-defines TraceSwitch2,
making any conditional Trace statements in your code evaluate to false and not print. The remove element provides
a way to turn a switch off, which is an alternative to deleting, commenting, or setting a value to 0 (assuming that 0
represents a condition that prevents trace output) of an existing switch.
Besides using configuration files, you can change switch settings dynamically in code. For example, the following
code modifies the TraceLevel setting to None for a TraceSwitch:
switch1.Level = TraceLevel.Off;
If you needed to dynamically set the switch on a custom switch, you should provide a property that accepts an enum
for the custom switch type. The implementation of that property can get and set base.SwitchSetting appropriately.
The following property implements this for the custom switch described in the Custom Switches section of this article:
You use tracing so you can collect run time information from your application to diagnose problems. This means that
there is a location where you can obtain the information, which is where trace listeners come in. A trace listener is a
type that allows you to persist your trace information to a location where it can be stored and analyzed. .NET ships
with three built-in trace listeners: DefaultTraceListener, TextWriterTraceListener, and EventLogTraceListener.
Using DefaultTraceListener
The DefaultTraceListener, as its name implies, is where .NET automatically sends all trace output. The output is sent
to a Win32 API called OutputDebugString. In Visual Studio .NET, the DefaultTraceListener output appears in
the Output window.
You can use trace listeners to control output destination including debug output, console, or the Windows Event Log.
pg. 66
C# ( Sharp ) Complete Notes
You can configure a given application with multiple trace listeners. When this occurs, each write operation will be
routed to every trace listener installed. Additionally, .NET shares all trace listeners with the Debug and Trace classes,
regardless of what switch they are using.
The Listeners property of the Trace class exposes a ListenersCollection type, which implements IList. This means
that if you prefer not to have output sent to the DefaultTraceListener you can use the Remove method as follows:
Using TextWriterTraceListener
A TextWriterTraceListener writes trace output to a file. To use it, instantiate a TextWriterTraceListener class and
add it to the Listeners collection. Listing 7 shows you how to set up a TextWriterTraceListener.
The code in Listing 7 creates a file stream and passes it to the TextWriterTraceListener, which will then write trace
output to the TraceDemo.log file as well as to all the other trace listeners in the Listeners collection.
Using EventLogTraceListener
Another trace listener that ships with .NET is the EventLogTraceListener, which writes to the Windows Event
Log. Listing 8 shows how to use the EventLogTraceListener.
The code in Listing 8 adds an EventLogTraceListener type to the Trace class Listeners collection, along with other
listeners. The algorithm automatically starts the mmc snap-in for the Windows Event Viewer so you can see the new
entry.
Creating a Custom Trace Listener
The trace listeners that ship with .NET are good for most applications. However, you may need to direct trace output
to another destination that the existing trace listeners don't support. For example, suppose you want to send trace
output to a database or maybe output to a special window in your application? Fortunately, you can use types in the
.NET Framework Library to create a custom trace listener.
When existing trace listeners don't meet your needs, you can create your own.
All trace listeners inherit the TraceListener class, an abstract class providing default behavior and virtual methods for
you to override in your own custom trace listener. The TraceListener class has abstract
Write and WriteLine methods that take a single string as a parameter. Listing 9 shows the implementation of the
custom trace listener.
The demo in Listing 9 contains a custom trace listener, WindowTraceListener, which opens a Windows Form and
writes trace output to a text box. The WindowTraceListener class inherits TraceListener. Its implementation is
minimal, overriding only the required Write and WriteLine methods, but Listing 9 demonstrates how easy it is to
create a custom trace listener. You will want to override all of the virtual overloads of the TraceListener class
for Write, WriteLine, Fail, and Assert for a more robust implementation.
pg. 67