weclome to ic0de.ws Check here


Thread Rating:
  • 1 Vote(s) - 5 Average
  • 1
  • 2
  • 3
  • 4
  • 5
C# Tutorial [WIP]
#1
C# tutorial for beginners


This is a tutorial for beginners, so I'll try to explain everything as simple as possible, but it helps if you have some programming experience already.
The tutorial assumes you're using VS 2017 or later.

This tutorial is incomplete, and is being actively worked on. Any feedback is highly appreciated.
I'll use simple names for all types, methods, parameters, and so on to make it as easy as possible for the reader. Of course you should use meaningful names for your own programs!

Table of contents:
  1. About C#
  2. Data Types
  3. Classes
  4. Structs
  5. Properties
  6. Methods
  7. Parameters
  8. Operators


1. About C#


C# is a statically typed, general-purpose, multi-paradigm programming language developed by Microsoft, along with other languages like F# and VB.NET. It is compiled to the Common Intermediate Language (CIL) which allows it to execute on various platforms. C# is strongly typed and uses the types of the .NET Framework, allowing it to interoperate with e.g. F#.

Its current version is 8.0, if you're using Visual Studio 2019 (version 16.3). Visual Studio 2017's C# version is 7.3.

Some of the most important features of C# are:
  • automatic garbage collection
  • indexers
  • generics
  • null conditional/coalesce operators
  • multithreading
  • delegates
  • LINQ (Language Integrated Query)
  • properties (also automatic generated ones)
  • extension methods
  • and much more coming with C# 8
1.1 Basic program structure

C# has a pretty simple structure which is based on namespaces and type definitions. The following is taken from the default template of a console application (.NET Core) in VS 2019:
Code:
using System; //using directives import all types from the specified namespace

namespace ConsoleApp //your root namespace; this is used to group types
{
    class Program // the class
    {
        static void Main(string[] args) //the entry point method
        {
            Console.WriteLine("Hello World!"); //write "hello world" to the console
        }
    }
}
[-] The following 2 users Like milkwalker's post:
  • 0xadmin, LoggyDogDog
Reply
#2
Nice. Hope to see more tutorials about this Big Grin
There is s_e_x without love, and there is love without s_e_x.
Then there is me, without both.
Reply
#3
2. Data Types


There are 3 types of data in C#:
  • values
  • references
  • pointers
2.1 Value Types


In this post we'll take a closer look at value types.
In C#, value types are mostly used for numbers. The following is an overview of all primitive value types:

  1. bool or Boolean, true or false
  2. byte or Byte, 0 to 255
  3. char or Char, u/0000 to u/ffff
  4. decimal or Decimal, (-7.9 x 1028 to 7.9 x 1028) / 100 to 28
  5. double or Double, (+/-)5.0 x 10-324 to (+/-)1.7 x 10308
  6. float or Single, -3.4 x 1038 to + 3.4 x 1038
  7. int or Int32, -2,147,483,648 to 2,147,483,647
  8. long or Int64, -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
  9. sbyte or SByte, -128 to 127
  10. short or Int16, -32,768 to 32,767
  11. uint or UInt32, 0 to 4,294,967,295
  12. ulong or UInt64, 0 to 18,446,744,073,709,551,615
  13. ushort or UInt16, 0 to 65,535
The default value for all numeric types is 0, the default for boolean types is false.


A declaration of a value type variable looks like the following:

Code:
int x = 10;
or
Code:
Int32 x = 10;

In this case, x is equal to 10.


C# supports explicit and implicit value type conversions, demonstrated by the following examples:

Code:
int x = 10;
short y = (short)x; //y is 10

Code:
short x = 10;
int y = x;

As you can see, the first example requires a so-called cast, an explicit conversion, because int is not implicitely conversible to short because of their respective ranges.

Consider the following example:

Code:
int x = 32768; x is short's max value + 1
short y = (short)x; //y is -32768

Here, y is -32768, because the conversion causes an overflow.

You should try to avoid overflows, to avoid unwanted results; that's why you should always use appropriate data types like int or even long.

Another important thing to consider is C#'s behavior when copying value types. In the above examples, you can see that a value is copied from one variable to another.
That means, if you copy and modify (mutate) a value, the original value stays the same:

Code:
int x = 10;
int y = x;
y = 15; //x is still 10

If you want to copy/mutate reference types, it behaves differently; we'll talk about that later.

2.2 Reference Types

Reference types - or class objects - are complex data structures which point to a memory location instead of containing a value.
Most of the ref types you'll encounter (including strings) are classes.

The following example shows how to declare a class:

Code:
public class Class1
{
}

We will talk about classes, their modifiers, and how to use them in one of the next posts
[-] The following 2 users Like milkwalker's post:
  • 0xadmin, LoggyDogDog
Reply
#4
3. Classes


As we have learned already, classes are used to define reference types.

The simplest definition of a class could look like the following code:
Code:
public class Class1
{
}

Obviously, the "class" keyword is needed to define a class, but what about "public"?

The "public" keyword is one of the so-called access modifiers; the most common ones are:
  • public, everyone can see and use the class or member
  • internal, only the current assembly can use the class or member
  • private, only the class can see and use the member (note: this is not valid for classes)
  • protected, only the current class and its subclasses can see and use the member (note: this is not valid for classes)
To define an internal class, simply omit the access modifier:
Code:
class Class1 //this class is internal
{
}

There are other keywords you might encounter, the most important ones are:
  • partial, you can split the class up
  • sealed, you can't inherit from this class (more on inheritance later)
  • static, you can't instantiate the class
  • abstract, you can't instantiate the class, but you can use this as base class (more on this later)
When using the partial keyword, this is valid syntax, otherwise it would yield a syntax error:
Code:
public partial class A
{
}

public partial class A
{
}


Consider the following class:
Code:
public class Class1
{
    public Class1() { }
}

The thing inside the class is our first so-called constructor, which is needed to create an object - or instance - of the class. It is invoked like this:
Code:
Class1 c = new Class1();
Note the "new" keyword.

You can define multiple constructors, as long as they have different signatures - that means, if they differ in their parameters. Here's an example:
Code:
public class Class1
{
    public Class1() { }

    public Class1(string s) { }

    public Class1(int i) { }
}

Now you can instantiate the class using the different constructors:
Code:
Class1 c1 = new Class1(); //the default constructor
Class1 c2 = new Class1("hello world"); //the constructor which has the string param
Class1 c3 = new Class1(10); //the constructor which has the int param
The constructors are being inferred from their parameters.

Now, why do we need constructors, why are they a useful thing?
As their name may suggest, their aim is to simplify object construction; consider the following class:
Code:
public class Class1
{
    string strValue;

    public Class1(string s)
    {
        strValue = s;
    }
}

In this case, "strValue" is a field of the class; basically a variable which is contained in every instance of the class.
The class' constructor initializes the field with the value passed as parameter:
Code:
Class1 c = new Class1("hello world");
//c.strValue is "hello world"

But beware: fields should not be used to hold public data. C# provides a comfortable way to do this: properties.
The most simple way to define a property:
Code:
public class Class1
{
    public string StrValue { get; set; }

    public Class1() { }

    public Class1(string s)
    {
        StrValue = s;
    }
}
The { get; set; } syntax is being compiled to get and set methods, which properly encapsulate the object's data.

If your class contains properties and you don't want to, or you can't use constructors, you could use the object initializer syntax, which would look like this in our case:
Code:
Class1 c = new Class1()
{
    StrValue = "hello world"
};
//Class1.StrValue is "hello world"

The above syntax is syntactic sugar for the more common initializer syntax which looks like this:
Code:
Class1 c = new Class1();
c.StrValue = "hello world";

There is no difference between them except their syntax; in fact, the former syntax is being converted to the latter one.

Remember the "static" keyword?
"static" is used for classes which do not require instances:
Code:
public static class Class1
{
    public static string StrValue { get; set; }
}

Static classes require their members to be static as well.

Now, how to use static classes?
The answer is simple: just invoke their members by using the class name:
Code:
Class1.StrValue = "hello static world";

Copying references does not behave like copying values, consider the following example:
Code:
Class1 c = new Class1();
Class1 copy = c;
copy.StrValue = "hello world";
//now c.StrValue and copy.StrValue are "hello world", because the two variables point to the same memory address

In the next posts I'll show you how we define value types, and other ways to define properties.
[-] The following 2 users Like milkwalker's post:
  • 0xadmin, LoggyDogDog
Reply
#5
4. Structs

Structs are a way to define custom value types, but this is rather uncommon. They mostly behave like classes regarding their syntax, constructors, and members.

The syntax for structs is:
Code:
public struct Struct1
{
}

The difference to a class' constructors is, that you have to initialize all properties of the struct in its constructor:
Code:
public struct Struct1
{
    public int Value { get; set; }

    public Struct1(int value)
    {
        Value = value;
    }
}

Use the "new" operator to create a struct's instance:
Code:
Struct1 s = new Struct1(10);
//s.Value is 10

If you call the struct's default constructor without passing any arguments, the properties keep their default values:
Code:
Struct1 s = new Struct1();
//s.Value is 0
[-] The following 2 users Like milkwalker's post:
  • 0xadmin, LoggyDogDog
Reply
#6
Im extremely happy with your work!!!
[Image: BezlSXT.gif]
[-] The following 2 users Like 0xadmin's post:
  • LoggyDogDog, milkwalker
Reply
#7
5. Properties

Now let's have a deeper insight into properties.
As you've already learnt, properties are being used to encapsulate public members of a struct or class; their syntax is:
Code:
public int Value { get; set; }
Where "get" and "set" are keywords to tell the compiler to generate Get and Set methods for the properties.

In other programming languages you would write it like this:
Code:
private int value;

public int GetValue()
{
    return value;
}

public void SetValue(int v)
{
    value = v;
}

Auto-implemented properties are syntax sugar for the above methods.

C# also supports read-only properties; to define one, just omit the set accessor:
Code:
public int Value { get; }

If you want to prevent set access from other classes, simply decorate the accessors with the private access modifier:
Code:
public int Value { get; private set; }
Note: this works with all simple access modifiers (private, protected, internal), but not public, because it is public by default.


The compiler generates a backing field for each property. Sometimes you have to have your own backing fields; the following example shows how to do this:
Code:
private int intValue;

public int IntValue
{
    get { return intValue; }
    set { intValue = value; } //"value" is a keyword, it contains the new value set by the caller
}

C# also supports so-called expression bodies for accessors, which would look like this in our case:
Code:
private int intValue;

public int IntValue
{
    get => intValue;
    set => intValue = value;
}
Their aim is to clean up one-liner methods to make them easier to read.

Code:
public int IntValue
{
    get => intValue;
    set
    {
        intValue = value;
        System.Diagnostics.Debug.WriteLine("intValue has changed. New value: " + value);
    }
}
This example shows one use-case for custom setters: a message is being written to the debug output as soon as the value is being changed.
Custom setters allow you to observe the value; if it changes, you can take appropriate action, such as updating other values or your user interface.

Have fun playing around with classes, structs, and their properties!
[-] The following 1 user Likes milkwalker's post:
  • LoggyDogDog
Reply
#8
6. Methods

We have already seen some examples of methods in the previous posts; now let's have a deeper insight. Methods are a way to encapsulate code and call it using a specific name and signature.

Remember the code example in the first post? It contains a method which looks like this:
Code:
public static void Main(string[] args)
{
    Console.WriteLine("Hello World!");
}

You can divide the method into several parts:
  1. public, the access modifier
  2. static, an additional modifier
  3. void, the return type
  4. Main, the name
  5. (string[] args), the parameters
  6. { ... }, the body

Let's talk about the return type of a method. Methods can have exactly one return type which either contains a value, a reference, or just nothing.

Return a value and save it to a variable:
Code:
public int ReturnValue()
{
    return 1;
}

int i = ReturnValue(); //call the method by its name

Return nothing:
Code:
public void ReturnNothing()
{
}

//note: you can't assign void to a variable; this WON'T work: var v = ReturnNothing();

As you can see, the method which has the void return type does not need to have a return statement; but if a method has any other return type, it must have a return statement.


Parameters provide a way to re-use the same code with different variables; the following example illustrates this:
Code:
public void DoSomething(int i)
{
    Console.WriteLine("parameter value: " + i);
}

Now, if you call the above method like
Code:
DoSomething(10);
it writes "parameter value: 10" to the console.


C# allows us to have several methods with the same name, yet they have to have different signatures. That means, they have to differ in their parameters:
Code:
public void DoSomething(int i)
{
    Console.WriteLine("parameter value: " + i);
}
Code:
public void DoSomething(string s)
{
    Console.WriteLine("parameter value: " + s);
}

When calling the method, the compiler will infer the correct so-called overload:
Code:
DoSomething(10); //this calls the first overload

DoSomething("hello"); //this calls the second overload


There are several types of parameters such as out, in, and ref. We'll talk about them later, for now let's focus on another cool feature of C#: default parameter values.
You can assign compile time constants to parameters, that means we could rewrite the above example like this:
Code:
public void DoSomething(int i = 10)
{
    Console.WriteLine("parameter value: " + i);
}
which allows us to call it like that:
Code:
DoSomething();
and it yields the exact same output "parameter value: 10", because we have assigned "10" as default value for the parameter.
[-] The following 2 users Like milkwalker's post:
  • 0xadmin, LoggyDogDog
Reply
#9
7. Parameters
In this post I'll talk about various types of parameters. As we have learnt already, parameters are being used to pass arguments to methods.
There are
  • simple params
  • out params
  • in params
  • ref params
  • this params
Look at the previous post if you want to learn something about simple parameters. In this post I'll give you some examples for the other types.


Let's start with out: this parameter type allows you to add another return type to a method. Example:
Code:
public static void Double(int i, out int outValue)
{
    outValue = i * 2;
}
You can call the method like this:
Code:
Double(5, out int result);
Here, the result variable contains 10.


in parameters are the opposite of out; the following example yields a syntax error, because in marks the passed value as read-only:
Code:
public static void DoSomething(in string s)
{
    s = "asd"; //this does NOT compile
}


ref parameters are like out, except they modify the reference instead of returning a new value:
Code:
public static void Double(ref int i)
{
    i = i * 2;
}
When called like this:
Code:
int i = 5; //note: you can't pass a value or property directly, a variable is needed to call this method
Double(ref i);
i now is equal to 10.


this parameters are being used to mark methods as extension methods. That means they can be used as static method or as a method that acts like an instance method. They allow us to extend the members of i.e. a system type:
Code:
public static int Double(this int i) //note: the this param has to be the first param of a method
{
    return i * 2;
}
Now you can consume the method like this:
Code:
int i = 5;
int j = i.Double();
Or like a normal static method:
Code:
int i = 5;
int j = Double(i);


By the way, there's another cool feature of C#: you don't actually need variables of a type to call their instance members. If you want to use a constant or a value that you just need once, you can call the method directly on this value. Using the above extension method, it would look like this:
Code:
int i = 5.Double();
[-] The following 1 user Likes milkwalker's post:
  • LoggyDogDog
Reply
#10
8. Operators


There is a variety of operators in C#, some of them are needed to perform calculations or assignments, others are just syntax sugar for common expressions.
Let's take a look at the most important operators:


=
Code:
int i = 1; //assigns a value to a variable or property

+
Code:
int i = 5 + 5; //adds two or more values

-
Code:
int i = 15 - 5; //subtracts two or more values

*
Code:
int i = 2 * 5; //multiplies two or more values

/
Code:
int i = 100 / 10; //divides two or more values

%
Code:
int i = 10 % 3; //calculates the remainder (would be 1 in this case)

++
Code:
int i = 0;
i++; //increments the value by 1

--
Code:
int i = 1;
i--; //decrements the value by 1


==
Code:
int i = 1, j = 1;
bool b = i == j; //checks whether two values are equal

!=
Code:
int i = 1, j = 2;
bool b = i != j; //checks whether two values are not equal

>
Code:
int i = 2, j = 1;
bool b = i > j; //checks whether a value is greater than another value

<
Code:
int i = 1, j = 2;
bool b = i < j; //checks whether a value is less than another value

>=
Code:
int i = 2, j = 1;
bool b = i >= j; //checks whether a value is greater than or equal to another value

<=
Code:
int i = 1, j = 2;
bool b = i <= j; //checks whether a value is less than or equal to another value



&&
Code:
bool a = true, b = true;
bool c = a && b; //checks whether all bools are true

||
Code:
bool a = false, b = true;
bool c = a || b; //checks whether one or more of the bools is true

!
Code:
bool a = false;
bool b = !a; //negates the bool; b is true



&
Code:
int i = 10, j = 12;
int k = i & j; //calculcates the bitwise AND

|
Code:
int i = 10, j = 12;
int k = i | j; //calculcates the bitwise OR

^
Code:
int i = 10, j = 12;
int k = i ^ j; //calculcates the bitwise XOR

<<
Code:
int i = 10, j = 2;
int k = i << j; //shifts two bits to the left

>>
Code:
int i = 10, j = 2;
int k = i >> j; //shifts two bits to the right

~
Code:
int i = 10;
int k = ~i; //flips all bits



You can combine most of the above operators with the assignment operator (=):
Code:
int i = 8;
i = i + 2;
becomes
Code:
int i = 8;
i += 2;


Valid combinations are: +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=, and new with C# 8, ??= (see the next section to learn about this one).



? : (conditional operator, also called ternary operator)
Code:
bool b = true;
int i = b ? 1 : 0; //evaluates the bool and returns the first value if true, otherwise the second value; i is 1

?. (null-conditional operator, also called null propagating operator)
Code:
string s = null;
string s2 = s?.Concat("asd"); //checks whether s is null and returns null if so; s2 is also null

?? (null coalesce operator)
Code:
string s = null;
string s2 = s ?? "hello"; //checks whether s is null and returns the other value if so

is
Code:
string s = "";
bool b = s is string; //checks whether the variable is an instance of the specified type

as
Code:
string s = "";
string s2 = s as string; //tries to cast the value to the specified type and returns null if the conversion fails

nameof
Code:
string s = "";
string s2 = nameof(s); //returns the variable name

typeof
Code:
Type t = typeof(string); //returns the type

sizeof
Code:
int i = sizeof(int); //returns the struct's size in bytes
[-] The following 1 user Likes milkwalker's post:
  • Xyt0
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)