Welcome!

Join our community of MMO enthusiasts and game developers! By registering, you'll gain access to discussions on the latest developments in MMO server files and collaborate with like-minded individuals. Join us today and unlock the potential of MMO server development!

Join Today!

C# Language features/tips/tricks

JavaScript Is Best Script
Joined
Dec 13, 2010
Messages
631
Reaction score
131
I've decided to write an article today to introduce and show you guys examples of some really cool and neat as well as some useful but uncommonly used features, tips and tricks of the C# language.

NOTES/REQUEST :
1) Some of these may be very common, so please, do inform me if i somehow deserve the title of "Captain Obvious"
2) Contents are .NET 4.5 compliant
3) If i have made any spelling/grammar/syntax/coding/BB mistakes, please feel free to correct me.
4) If i have you spot inaccurate or incorrect terminology, feel free to notify me.
5) Should you have any things you would like me to include, feel free to post them here.
6) Please, criticize where necessary.

Content :
1) Ternary operators
2) Properties
3) the null-coalescing operator
4) The "var" keyword
5) Namespace Aliases
6) Shared value assignment
7) Generics
8) The "default" keyword
9) Tasks, await and async
10) Delegates and Lambda expressions

All right then! Let's get down to business.

Ternary operators
Lets say we have an apple tree and we wanna set the number of apples it has. Obviously, the apple tree can't have a negative number of apples, so we're gonna needa do some validation to make sure that the number of apples set is non-negative. You would usually do this:

Code:
if (count < 0)
    ApplesCount = 0;
else
    ApplesCount = count;

Well, here's what a ternary operator does:

Code:
ApplesCount = count < 0 ? 0 : count;

Basically, a ternary operator checks whether the condition before the '?' is true. If it is, it uses the value specified between '?' and ':', else, it uses the value specified after ':'

You could also do some chaining:

Code:
ApplesCount = count < 0 ? 0 : count < 30 ? count : 30;

Which is equivalent to:

Code:
if (count < 0)
    ApplesCount = 0;
else if (count < 30)
    ApplesCount = count;
else
    ApplesCount = 30;



The null-coalescing operator
Let's say you have a nullable variable and you wanna return a specific value it it's null, or the variable itself if it's not null:
Code:
int? ApplesCount;

public static int GetApplesCount()
{
    return (int)(ApplesCount == null ? 1 : ApplesCount);	
}

It could all be shorten to:
Code:
int? ApplesCount;

public static int GetApplesCount()
{
    return ApplesCount ?? 1; // double '?'s	
}

Basically, if variable on left of '??' is null, it returns value on right of '??', else, it returns the variable itself.
It's not very significant a change in this example, but let me demonstrate how useful it can get:
Code:
int? a, b, c, d, e, f, g;

public static int GetFirstNonNull()
{
    return a != null ? a : b != null ? b : c != null ? c : d != null ? d : e != null ? e : f != null ? f : g != null ? g : 1; // If you're still getting used to ternary operators, this means : "If a not null then a else if b not null then b else if ....."
}
can be shortened quite a bit to :
Code:
    static int? a, b, c, d, e, f, g;

    public static int GetFirstNonNull()
    {
        return (int)(a ?? b ?? c ?? d ?? e ?? f ?? g ?? 1);
    }



Properties
Using the previous examples, let's say you have a class named "AppleTree" which represents an ordinary apple tree and a field named "ApplesCount" which represents the number of apples the tree has.
Code:
class AppleTree
{
    public int ApplesCount;
}

Then, whenever you wanna get or set the number of apples the tree has, you would access the field "ApplesCount" normally as follows:
Code:
int applesIHave = tree.ApplesCount; // Note that "tree" is assumed to be an instance "AppleTree"
tree.ApplesCount = 100;

Perfectly normal, but what if you need validation?
What if you want to make sure that whenever you set the number of apples a tree has, the value that you passed in as an argument isn't negative, or isn't too big?
Sure, you'll think of modifying the class "AppleTree" as follows (I'm sure many Java programmers will, no offense though) :
Code:
class AppleTree
{
    private int ApplesCount; // Note that i make it private here so users won't be able to access it and have to go thru validation via SetApplesCount

    public int GetApplesCount() // This is necessary, because you can't access "ApplesCount" from outside anymore now that it's private
    {
        return this.ApplesCount;
    }

    public void SetApplesCount(int count)
    {
        this.ApplesCount = count < 0 ? 0 : count < 30 ? count : 30;
    }
}

Then, to get or set WITH validation the number of apples a tree has, you do:
Code:
int applesIHave = tree.GetApplesCount();
tree.SetApplesCount(-100);

In the above example, "SetApplesCount" will validate the argument passed in. Since the argument passed in is negative, the private field "ApplesCount" in the particular instance of an "AppleTree" will be set to 0 instead of -100;

Whew, we've finally managed to implement validation for fields. Validation is extremely useful and important and has a wide range of applications. It's used when some fields can theoretically be negative but cannot practically (like for example, number of hairs my scalp has cannot be negative). But we needed to add in two methods to get and set WITH validation a specific field. There must surely be a better way to do this. This is where properties comes in.
Code:
class AppleTree
{
    private int _applesCount; // This is called the backing field of the property "ApplesCount" and it is recommended to be either private or protected
    public int ApplesCount
    {
        get
        {
            return this.ApplesCount; // Equivalent to GetApplesCount() in the previous example
        }

        set
        {
            this._applesCount = value < 0 ? 0 : value < 30 ? value : 30; // Equivalent to SetApplesCount(int count) in the previous example, just that now the parameter's name has been replaced with "value" insteaed of "count"
        }
    }
}

Then, we do the following:
Code:
int applesIHave = tree.ApplesCount;
tree.ApplesCount = -100; // Validation is done here, field is set to 0 according to validation.

This does exactly the same as the example using "GetApplesCount" and "SetApplesCount", but in my opinion, i honestly feel that the use of properties looks a lot much neater.



The "var" keyword
Lets say you have the a class in a certain namespace and you wanna create an instance of this specific class, but are just too lazy to add the namespace to the usings block:
Code:
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
Console.WriteLine(formatter.ToString());

Here comes the "var" keyword:
Code:
var formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();

Which has the same effect as the previous example.



Aliases
We assume that that there's a class, "AppleTree", located in the namespace "GardeningTools.FruitBearingTrees.TreesIDoNotLike".
However, there also happens to be another class of the same name located in the namespace "JohnsonWorld.FruityTrees.NiceTrees". We will then have to specify the namespace so that the compiler will know which AppleTree class the code is referring to. For example:
Code:
using GardeningTools.FruitBearingTrees.TreesIDoNotLike;
using JohnsonWorld.FruityTrees.NiceTrees;

public static void Main(string[] args)
{
    var shortTree = new GardeningTools.FruitBearingTrees.TreesIDoNotLike.AppleTree();
    var tallTree = new JohnsonWorld.FruityTrees.NiceTrees();
    Console.WriteLine(shortTree.ApplesCount);
    Console.WriteLine(shortTree.Height);
}

What if we have to refer to both classes in both namespace several times in a specific piece of code? Won't it be very very tiring and error prone? Well one way to alleviate this is to use Aliases:
Code:
using ATreesAlias;
using BTreesAlias;

public static void Main(string[] args)
{
    var shortTree = new ATreesAlias.AppleTree();
    var tallTree = new BTreesAlias.AppleTree();
    Console.WriteLine(shortTree.ApplesCount);
    Console.WriteLine(shortTree.Height);
}

Which simplifies things quite a bit. One practical example is the ambiguity of the usage of "Point" in XNA Programming, which could refer to System.Drawing.Point or Microsoft.Xna.Framework.Point (just in case you happen to need both namespaces)

Even neater still, lets say throughout a piece of code you require the usage of the class "KeyValuePair<KeyValuePair<short,int>,KeyValuePair<short, byte>>":
Code:
public static void Main(string[] args)
{
    var a = new KeyValuePair<KeyValuePair<short,int>,KeyValuePair<short, byte>>();
    var b = new KeyValuePair<KeyValuePair<short,int>,KeyValuePair<short, byte>>();
    var c = new KeyValuePair<KeyValuePair<short,int>,KeyValuePair<short, byte>>();
}

It's a tad tiring, no? Well, Aliases are here to save the day again:
Code:
using UserTypeAlias = KeyValuePair<KeyValuePair<short,int>,KeyValuePair<short, byte>>;

public static void Main(string[] args)
{
    var a = new UserTypeAlias();
    var b = new UserTypeAlias();
    var c = new UserTypeAlias();
}



Shared value assignment
Lets say you have 6 int variables and you wanna assign the same value to them:
Code:
class AppleTree
{
    private int applesCount, height, width, age, rootsCount, thickness;

    public AppleTree()
    {
        applesCount = 1;
        height = 1;
        width = 1;
        age = 1;
        rootsCount = 1;
        thickness = 1;
    }
}

Personally, i feel that this is very very tedious, especially in instances where up to 20 variables of the same type has to be assigned with the same value. This is where shared initialization comes in:
Code:
class AppleTree
{
    private int applesCount, height, width, age, rootsCount, thickness;

    public AppleTree()
    {
        applesCount = height = width = age = rootsCount = thickness = 1;
    }
}



Generics
You want to create an custom class which is able to store, retrieve, and assign elements of the SAME CLASS:
Code:
class NumberCollection
{
    private object[] array;

    public NumberCollection(int size)
    {
        this.array = new object[size];
    }

    public object GetElementAt(int index)
    {
        return array[index];
    }

    public void SetElementAt(int index, object value)
    {
        array[index] = value;
    }
}

Seems legit, doesn't it? But the problem with this is the compiler will not be able to recognize the type of the objects used:
Code:
var col = new NumberCollection(5);
col.SetElementAt(0, 100);
col.SetElementAt(2, 200);
int total = col.GetElementAt(0) + col.GetElementAt(2);// THIS will throw an error! because GetElementAt returns an object insteaed of an int, the type of the objects that were passed in, and the '+' operator cannot be used on objects!

How in then, do we get the compiler to recognize what type the objects are assigned? Generic classes, are the way to go:
Code:
class NumberCollection<T> //Tells the compiler that type of the objects are of type T, a type variable
{
    private T[] array; //Declares an array of the same T

    public NumberCollection(int size)
    {
        this.array = new object[size];
    }

    public T GetElementAt(int index) //Returns an object of the same type T
    {
        return array[index];
    }

    public void SetElementAt(int index, T value) //Assigns a value of the same type T
    {
        array[index] = value;
    }
}

To utilize this generic class:
Code:
var col = new NumberCollection<int>(5); //initializes an instance of a "NumberCollection", passing in the type "int" as a type argument. The "T" in the class will now represent "int" for this specific instance.
col.SetElementAt(0, 100);
col.SetElementAt(2, 200);
int total = col.GetElementAt(0) + col.GetElementAt(2); // Now, GetElementAt returns an int instead of just an object, which overloads the '+' operator
Console.WriteLine(total); // Outputs "300".

You could specify multiple type parameters too, just like Dictionary<TKey, TValue> does.
Here, TKey is represents the type of the key while TValue represents the type if the value and you use it as :
Code:
var englishDict = new Dictionary<string, string>() // Passes the respective type arguments into the constructor
englishDict.Add("Apple", "A tasty looking red-colored fruit");
englishDict.Add("Banana", "Some yellow and long fruit");
Console.WriteLine("Unofficial definition of banana : " + englishDict["Banana"]);

Generics are not just restricted to classes, it can be used for methods too :
Code:
public static KeyValuePair<int,int> Swap<T>(T a, T b)
{
    T temp = a;
    a = b;
    b = temp;
    return new KeyValuePair<int,int>(a, b);
}
and this generic method can be called it as follows:
Code:
Swap<long>(123,456);



The "default" keyword
You have an object and you don't know it's type, but you wanna convert it into a variable type. If it doesn't work, then return the default value.
But how? the default value of a type depends on a type. For example, the default value of "Point" isn't the default value of "int". This is where the "default" keyword comes in:
Code:
public static T CastOrDefault<T>(object obj)
{
    return obj is int ? (int)obj : default(T); // Note that the "is" keyword returns true if the type of the object on the left of "is" is the same as the specified type on the right-side of the "is", false if not.
}
and you call this generic method as follows:
Code:
Console.WriteLine(CastOrDefault<int>("potato")); // outputs 0, because "potato" cannot be converted into an int.



Tasks, await and async
Allow me to first introduce you to the world of Tasks.
By MSDN's definition, "Represents an asynchronous operation"
By my perception of a Task, a Task is a wrapper around Thread, adding in many many more powerful functionalities like return types, futures, cancellation tokens, pooling, etc.

Lets say, you wanna create a copy of an extremely large file without blocking the main thread:
Code:
    public static void Main(String[] args)
    {
        CopyTheLargeFileAsync();
        while(true);
    }

    public static void CopyTheLargeFileAsync()
    {
        Thread t = new Thread(() =>
        {
            using (var inputStream = File.Open(@"C:\veryLargeFile.avi", FileMode.Open))
            {
                using (var outputStream = File.Open(@"C:\outputFile.avi", FileMode.Create))
                {
                    inputStream.CopyTo(outputStream);
                    Console.WriteLine("File copied");
                }
            }
        });
	t.IsBackground = true;
        t.Start();
    }

Well, i don't know about you, but to me i think that it's super tedious and "messy" to create a new thread, and then start it altogether.
In fact, perhaps that's one of the reasons why Microsoft decided to implement async and await in C#:
Code:
    public static void Main(String[] args)
    {
        Console.WriteLine("Executed 1st");
        CopyTheLargeFileAsync(); // Calls the async method which appears to returns upon awaiting on a Task
        Console.WriteLine("Executed 3nd");
        while(true);
    }

    public static async void CopyTheLargeFileAsync()
    {
        using (var inputStream = File.Open(@"C:\veryLargeFile.avi", FileMode.Open))
        {
            using (var outputStream = File.Open(@"C:\outputFile.avi", FileMode.Create))
            {
                Console.WriteLine("Executed 2nd");
                await inputStream.CopyToAsync(outputStream); // Awaits upon a Task (CopyToAsync)
                // Here, execution of this function ONLY has been halted, and the appears to return to the calling thread
                // Execution of all following code for this function will resume as per normal ONLY after the awaited Task has completed (I.E. stream has been copied)
                // Note that all following code runs synchronously as per normal on a SEPERATE thread from which the function was called
                Console.WriteLine("Executed 4th"); // This line will be executed ONLY AFTER the Task being awaited on has completed
                Console.WriteLine("Executed 5th"); // This line will be executed only after the previous one, which will be executed only after awaited Task completes
            }
        }
        Console.WriteLine("Executed 6th");
    }

In the above example, the async method CopyTheLargeFileAsync awaits on an existing task (CopyToAsync).
But what if we wanna create our own task? Well that's simple, it's something like threads:
Code:
    public static void Main(String[] args)
    {
        Console.WriteLine("Executed 1st");
        CopyTheLargeFileAsync(); // Calls the async method which appears to return upon awaiting on a Task
        Console.WriteLine("Executed 3st");
        while(true);
    }

    public static async void CopyTheLargeFileAsync()
    {
        Console.WriteLine("Executed 2st");

        Task task = new Task(() =>
        {
            using (var inputStream = File.Open(@"C:\veryLargeFile.avi", FileMode.Open))
            {
                using (var outputStream = File.Open(@"C:\outputFile.avi", FileMode.Create))
                {
                    inputStream.CopyTo(outputStream);
                    Console.WriteLine("Executed 4th");
                }
            }
        }); // Creates a custom Task
        task.Start(); // Starts the task running

        await task; // Awaits on the created task and halts execution for the current funtion and appears to return to the calling thread
        
        Console.WriteLine("Executed 5th"); // Executed ONLY after awaited task completes execution. Note that if you did not Start the Task (I.E. task.Start()), it's the same as the Task not having completed.
    }

Right! Those are just to give you a rough idea of Tasks, async and await.
So far, all we've seen are methods and tasks that returns no value (I.E. of type void).
To create and use a Task with a method, we could do the following:
Code:
    public static void Main(String[] args)
    {
        CopyAndPrintTheFileAsync(); // Calls the async method which appears to return upon awaiting on a Task
        while (true) ;
    }

    public static async void CopyAndPrintTheFileAsync()
    {
        long length = await CopyTheLargeFileAsync(); // Awaits on the Task created and returned by CopyTheLargeFileAsync, hence appearing to return to the calling thread
        Console.WriteLine(length); // Occurs after awaited Task completes. By then, length will have been set by what has been returned by the awaited Task.
    }

    public static Task<long> CopyTheLargeFileAsync()
    {
        Task<long> task = new Task<long>(() =>
        {
            using (var inputStream = File.Open(@"C:\veryLargeFile.avi", FileMode.Open))
            {
                using (var outputStream = File.Open(@"C:\outputFile.avi", FileMode.Create))
                {
                    inputStream.CopyTo(outputStream);
                    return inputStream.Length; // returns the value as though it was in a normal method with return type long
                }
            }
        }); // Creates a Task
        task.Start(); // Starts the Task but DOES NOT await on it

        return task; // returns the started Task
    }

It is very confusing and you may experience a paradigm shift because it really exposes you to future and promises, which is real useful for parallel programming.
To be honest, i'm still getting used to Tasks so please do forgive me if what i've provided is inaccurate/insufficient.
I may do a sperate thread dedicated to these parallel features some day.
ApplesCount = 0;
else
ApplesCount = count;
[/CODE]

Well, here's what a ternary operator does:

Code:
ApplesCount = count < 0 ? 0 : count;

Basically, a ternary operator checks whether the condition before the '?' is true. If it is, it uses the value specified between '?' and ':', else, it uses the value specified after ':'

You could also do some chaining:

Code:
ApplesCount = count < 0 ? 0 : count < 30 ? count : 30;

Which is equivalent to:

Code:
if (count < 0)
    ApplesCount = 0;
else if (count < 30)
    ApplesCount = count;
else
    ApplesCount = 30;
[/SPOILER]



The null-coalescing operator
Let's say you have a nullable variable and you wanna return a specific value it it's null, or the variable itself if it's not null:
Code:
int? ApplesCount;

public static int GetApplesCount()
{
    return (int)(ApplesCount == null ? 1 : ApplesCount);	
}

It could all be shorten to:
Code:
int? ApplesCount;

public static int GetApplesCount()
{
    return ApplesCount ?? 1; // double '?'s	
}

Basically, if variable on left of '??' is null, it returns value on right of '??', else, it returns the variable itself.
It's not very significant a change in this example, but let me demonstrate how useful it can get:
Code:
int? a, b, c, d, e, f, g;

public static int GetFirstNonNull()
{
    return a != null ? a : b != null ? b : c != null ? c : d != null ? d : e != null ? e : f != null ? f : g != null ? g : 1; // If you're still getting used to ternary operators, this means : "If a not null then a else if b not null then b else if ....."
}
can be shortened quite a bit to :
Code:
    static int? a, b, c, d, e, f, g;

    public static int GetFirstNonNull()
    {
        return (int)(a ?? b ?? c ?? d ?? e ?? f ?? g ?? 1);
    }



Properties
Using the previous examples, let's say you have a class named "AppleTree" which represents an ordinary apple tree and a field named "ApplesCount" which represents the number of apples the tree has.
Code:
class AppleTree
{
    public int ApplesCount;
}

Then, whenever you wanna get or set the number of apples the tree has, you would access the field "ApplesCount" normally as follows:
Code:
int applesIHave = tree.ApplesCount; // Note that "tree" is assumed to be an instance "AppleTree"
tree.ApplesCount = 100;

Perfectly normal, but what if you need validation?
What if you want to make sure that whenever you set the number of apples a tree has, the value that you passed in as an argument isn't negative, or isn't too big?
Sure, you'll think of modifying the class "AppleTree" as follows (I'm sure many Java programmers will, no offense though) :
Code:
class AppleTree
{
    private int ApplesCount; // Note that i make it private here so users won't be able to access it and have to go thru validation via SetApplesCount

    public int GetApplesCount() // This is necessary, because you can't access "ApplesCount" from outside anymore now that it's private
    {
        return this.ApplesCount;
    }

    public void SetApplesCount(int count)
    {
        this.ApplesCount = count < 0 ? 0 : count < 30 ? count : 30;
    }
}

Then, to get or set WITH validation the number of apples a tree has, you do:
Code:
int applesIHave = tree.GetApplesCount();
tree.SetApplesCount(-100);

In the above example, "SetApplesCount" will validate the argument passed in. Since the argument passed in is negative, the private field "ApplesCount" in the particular instance of an "AppleTree" will be set to 0 instead of -100;

Whew, we've finally managed to implement validation for fields. Validation is extremely useful and important and has a wide range of applications. It's used when some fields can theoretically be negative but cannot practically (like for example, number of hairs my scalp has cannot be negative). But we needed to add in two methods to get and set WITH validation a specific field. There must surely be a better way to do this. This is where properties comes in.
Code:
class AppleTree
{
    private int _applesCount; // This is called the backing field of the property "ApplesCount" and it is recommended to be either private or protected
    public int ApplesCount
    {
        get
        {
            return this.ApplesCount; // Equivalent to GetApplesCount() in the previous example
        }

        set
        {
            this._applesCount = value < 0 ? 0 : value < 30 ? value : 30; // Equivalent to SetApplesCount(int count) in the previous example, just that now the parameter's name has been replaced with "value" insteaed of "count"
        }
    }
}

Then, we do the following:
Code:
int applesIHave = tree.ApplesCount;
tree.ApplesCount = -100;

This does exactly the same as the example using "GetApplesCount" and "SetApplesCount", but in my opinion, i honestly feel that the use of properties looks a lot much neater.



The "var" keyword
Lets say you have the a class in a certain namespace and you wanna create an instance of this specific class, but are just too lazy to add the namespace to the usings block:
Code:
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
Console.WriteLine(formatter.ToString());

Here comes the "var" keyword:
Code:
var formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();

Which has the same effect as the previous example.



Aliases
We assume that that there's a class, "AppleTree", located in the namespace "GardeningTools.FruitBearingTrees.TreesIDoNotLike".
However, there also happens to be another class of the same name located in the namespace "JohnsonWorld.FruityTrees.NiceTrees". We will then have to specify the namespace so that the compiler will know which AppleTree class the code is referring to. For example:
Code:
using GardeningTools.FruitBearingTrees.TreesIDoNotLike;
using JohnsonWorld.FruityTrees.NiceTrees;

public static void Main(string[] args)
{
    var shortTree = new GardeningTools.FruitBearingTrees.TreesIDoNotLike.AppleTree();
    var tallTree = new JohnsonWorld.FruityTrees.NiceTrees
    Console.WriteLine(shortTree.ApplesCount);
    Console.WriteLine(shortTree.Height);
}

What if we have to refer to both classes in both namespace several times in a specific piece of code? Won't it be very very tiring and error prone? Well one way to alleviate this is to use Aliases:
Code:
using ATreesAlias;
using BTreesAlias;

public static void Main(string[] args)
{
    var shortTree = new ATrees.AppleTree();
    var tallTree = new BTrees.AppleTree();
    Console.WriteLine(shortTree.ApplesCount);
    Console.WriteLine(shortTree.Height);
}

Which simplifies things quite a bit. One practical example is the ambiguity of the usage of "Point" in XNA Programming, which could refer to System.Drawing.Point or Microsoft.Xna.Framework.Point (just in case you happen to need both)

Even neater still, lets say throughout a piece of code you require the usage of the class "KeyValuePair<KeyValuePair<short,int>,KeyValuePair<short, byte>>":
Code:
public static void Main(string[] args)
{
    var a = new KeyValuePair<KeyValuePair<short,int>,KeyValuePair<short, byte>>();
    var b = new KeyValuePair<KeyValuePair<short,int>,KeyValuePair<short, byte>>();
    var c = new KeyValuePair<KeyValuePair<short,int>,KeyValuePair<short, byte>>();
}

It's a tad tiring, no? Well, Aliases are here to save the day again:
Code:
using UserTypeAlias = KeyValuePair<KeyValuePair<short,int>,KeyValuePair<short, byte>>;

public static void Main(string[] args)
{
    var a = new UserAlias();
    var b = new UserAlias();
    var c = new UserAlias();
}



Shared value assignment
Lets say you have 6 int variables and you wanna assign the same value to them:
Code:
class AppleTree
{
    private int applesCount, height, width, age, rootsCount, thickness;

    public AppleTree()
    {
        applesCount = 1;
        height = 1;
        width = 1;
        age = 1;
        rootsCount = 1;
        thickness = 1;
    }
}

Personally, i feel that this is very very tedious, especially in instances where up to 20 variables of the same type has to be assigned with the same value. This is where shared initialization comes in:
Code:
class AppleTree
{
    private int applesCount, height, width, age, rootsCount, thickness;

    public AppleTree()
    {
        applesCount = height = width = age = rootsCount = thickness = 1;
    }
}



Generics
You want to create an custom class which is able to store, retrieve, and assign elements of the SAME CLASS:
Code:
class NumberCollection
{
    private object[] array;

    public NumberCollection(int size)
    {
        this.array = new object[size];
    }

    public object GetElementAt(int index)
    {
        return array[index];
    }

    public void SetElementAt(int index, object value)
    {
        array[index] = value;
    }
}

Seems legit, doesn't it? But the problem with this is the compiler will not be able to recognize the type of the objects used:
Code:
var col = new NumberCollection(5);
col.SetElementAt(0, 100);
col.SetElementAt(2, 200);
int total = col.GetElementAt(0) + col.GetElementAt(2);// THIS will throw an error! because GetElementAt returns an object insteaed of an int, the type of the objects that were passed in, and the '+' operator cannot be used on objects!

How in then, do we get the compiler to recognize what type the objects are assigned? Generic classes, are the way to go:
Code:
class NumberCollection<T> //Tells the compiler that type of the objects are of type T, a type variable
{
    private T[] array; //Declares an array of the same T

    public NumberCollection(int size)
    {
        this.array = new object[size];
    }

    public T GetElementAt(int index) //Returns an object of the same type T
    {
        return array[index];
    }

    public void SetElementAt(int index, T value) //Assigns a value of the same type T
    {
        array[index] = value;
    }
}

To utilize this generic class:
Code:
var col = new NumberCollection<int>(5); //initializes an instance of a "NumberCollection", passing in the type "int" as a type argument. The "T" in the class will now represent "int" for this specific instance.
col.SetElementAt(0, 100);
col.SetElementAt(2, 200);
int total = col.GetElementAt(0) + col.GetElementAt(2); // Now, GetElementAt returns an int instead of just an object, which overloads the '+' operator
Console.WriteLine(total); // Outputs "300".

You could specify multiple type parameters too, just like Dictionary<TKey, TValue> does.
Here, TKey is represents the type of the key while TValue represents the type if the value and you use it as :
Code:
var englishDict = new Dictionary<string, string>() // Passes the respective type arguments into the constructor
englishDict.Add("Apple", "A tasty looking red-colored fruit");
englishDict.Add("Banana", "Some yellow and long fruit");
Console.WriteLine("Unofficial definition of banana : " + englishDict["Banana"]);

Generics are not just restricted to classes, it can be used for methods too :
Code:
public static KeyValuePair<int,int> Swap<T>(T a, T b)
{
    T temp = a;
    a = b;
    b = temp;
    return new KeyValuePair<int,int>(a, b);
}
and this generic method can be called it as follows:
Code:
Swap<long>(123,456);



The "default" keyword
You have an object and you don't know it's type, but you wanna convert it into a variable type. If it doesn't work, then return the default value.
But how? the default value of a type depends on a type. For example, the default value of "Point" isn't the default value of "int". This is where the "default" keyword comes in:
Code:
public static T CastOrDefault<T>(object obj)
{
    return obj is int ? (int)obj : default(T); // Note that the "is" keyword returns true if the type of the object on the left of "is" is the same as the specified type on the right-side of the "is", false if not.
}
and you call this generic method as follows:
Code:
Console.WriteLine(CastOrDefault<int>("potato")); // outputs 0, because "potato" cannot be converted into an int.



Tasks, await and async
Allow me to first introduce you to the world of Tasks.
By MSDN's definition, "Represents an asynchronous operation"
By my perception of a Task, a Task is a wrapper around Thread, adding in many many more powerful functionalities like return types, futures, cancellation tokens, pooling, etc.

Lets say, you wanna create a copy of an extremely large file without blocking the main thread:
Code:
    public static void Main(String[] args)
    {
        CopyTheLargeFileAsync();
        while(true); // Prevents the main thread from exiting
    }

    public static void CopyTheLargeFileAsync()
    {
        Thread t = new Thread(() =>
        {
            using (var inputStream = File.Open(@"C:\veryLargeFile.avi", FileMode.Open))
            {
                using (var outputStream = File.Open(@"C:\outputFile.avi", FileMode.Create))
                {
                    inputStream.CopyTo(outputStream);
                    Console.WriteLine("File copied");
                }
            }
        });
	t.IsBackground = true;
        t.Start();
    }

Well, i don't know about you, but to me i think that it's super tedious and "messy" to create a new thread, and then start it altogether.
In fact, perhaps that's one of the reasons why Microsoft decided to implement async and await in C#:
Code:
    public static void Main(String[] args)
    {
        Console.WriteLine("Executed 1st");
        CopyTheLargeFileAsync(); // Calls the async method which appears to returns upon awaiting on a Task
        Console.WriteLine("Executed 3nd");
        while(true); // Prevents the main thread from exiting
    }

    public static async void CopyTheLargeFileAsync()
    {
        using (var inputStream = File.Open(@"C:\veryLargeFile.avi", FileMode.Open))
        {
            using (var outputStream = File.Open(@"C:\outputFile.avi", FileMode.Create))
            {
                Console.WriteLine("Executed 2nd");
                await inputStream.CopyToAsync(outputStream); // Awaits upon a Task (CopyToAsync)
                // Here, execution of this function ONLY has been halted, and the appears to return to the calling thread
                // Execution of all following code for this function will resume as per normal ONLY after the awaited Task has completed (I.E. stream has been copied)
                // Note that all following code runs synchronously as per normal on a SEPERATE thread from which the function was called
                Console.WriteLine("Executed 4th"); // This line will be executed ONLY AFTER the Task being awaited on has completed
                Console.WriteLine("Executed 5th"); // This line will be executed only after the previous one, which will be executed only after awaited Task completes
            }
        }
        Console.WriteLine("Executed 6th");
    }

In the above example, the async method CopyTheLargeFileAsync awaits on an existing task (CopyToAsync).
But what if we wanna create our own task? Well that's simple, it's something like threads:
Code:
    public static void Main(String[] args)
    {
        Console.WriteLine("Executed 1st");
        CopyTheLargeFileAsync(); // Calls the async method which appears to return upon awaiting on a Task
        Console.WriteLine("Executed 3st");
        while(true); // Prevents the main thread from exiting
    }

    public static async void CopyTheLargeFileAsync()
    {
        Console.WriteLine("Executed 2st");

        Task task = new Task(() =>
        {
            using (var inputStream = File.Open(@"C:\veryLargeFile.avi", FileMode.Open))
            {
                using (var outputStream = File.Open(@"C:\outputFile.avi", FileMode.Create))
                {
                    inputStream.CopyTo(outputStream);
                    Console.WriteLine("Executed 4th");
                }
            }
        }); // Creates a custom Task
        task.Start(); // Starts the task running

        await task; // Awaits on the created task and halts execution for the current funtion and appears to return to the calling thread
        
        Console.WriteLine("Executed 5th"); // Executed ONLY after awaited task completes execution. Note that if you did not Start the Task (I.E. task.Start()), it's the same as the Task not having completed.
    }

Right! Those are just to give you a rough idea of Tasks, async and await.
So far, all we've seen are methods and tasks that returns no value (I.E. of type void).
To create and use a Task with a method, we could do the following:
Code:
    public static void Main(String[] args)
    {
        CopyAndPrintTheFileAsync(); // Calls the async method which appears to return upon awaiting on a Task
        while (true) ; // Prevents the main thread from exiting
    }

    public static async void CopyAndPrintTheFileAsync()
    {
        long length = await CopyTheLargeFileAsync(); // Awaits on the Task created and returned by CopyTheLargeFileAsync, hence appearing to return to the calling thread
        Console.WriteLine(length); // Occurs after awaited Task completes. By then, length will have been set by what has been returned by the awaited Task.
    }

    public static Task<long> CopyTheLargeFileAsync()
    {
        Task<long> task = new Task<long>(() =>
        {
            using (var inputStream = File.Open(@"C:\veryLargeFile.avi", FileMode.Open))
            {
                using (var outputStream = File.Open(@"C:\outputFile.avi", FileMode.Create))
                {
                    inputStream.CopyTo(outputStream);
                    return inputStream.Length; // returns the value as though it was in a normal method with return type long
                }
            }
        }); // Creates a Task
        task.Start(); // Starts the Task but DOES NOT await on it

        return task; // returns the started Task
    }

It is very confusing and you may experience a paradigm shift because it really exposes you to future and promises, which is real useful for parallel programming.
To be honest, i'm still getting used to Tasks so please do forgive me if what i've provided is inaccurate/insufficient.
I may do a sperate thread dedicated to these parallel features some day.



Delegates and Lambdas expressions
Lets say you have a block of code you wanna use for a specific purpose:
Code:
    public static void Main(String[] args)
    {
        Console.WriteLine(MeanOf(1, 2));
        while (true) ;
    }

    private static double MeanOf(int a, int b)
    {
        return (double)(a + b) / 2;
    }

This does work but at what costs?
Firstly, you had to add another function to the class.
Secondly, it only works specific arguments (I.E. You can't use it to get the average of 3 numbers).
This is where Delegates and Lambdas comes in:
Code:
    public static void Main(String[] args)
    {
        Func<int, int, double> mean = (int a, int b) => (double)(a + b) / 2;
        Console.WriteLine(mean(1, 2));
    }

Let me explain the delegate Func<in T1, in T2, in T3, ..., in Tn, out TResult>.
T1, T2, T3, ... , Tn are type parameters to be passed in to specify the types that the respective arguments are of.
TResult is the type parameter to be passed in to specify the type of the value that the lambda will return.

Now, for the lambda expression.
(int a, int b) on the left side of '=>' represents the parameters list (I.E. the input parameters).
What goes on the right side of '=>' will be evaluated with access to the parameters in the specified parameters list.

So essentially, the example with lambdas is the same as the one without, just that you did not have to create a new function all together for the same purpose.
Of course, the Func<int, int, double> can be reused just like an ordinary function:
Code:
    public static void Main(String[] args)
    {
        Func<int, int, double> mean = (int a, int b) => (double)(a + b) / 2;
        Console.WriteLine(mean(1, 2));
        Console.WriteLime(mean(2, 3));
        Console.WriteLime(mean(22, 13));
        Console.WriteLime(mean(27, 13));
        Console.WriteLime(mean(4, 5));
    }

So far, we've only looked at Func which is a delegate which requires a return type.
What if we wanted a delegate with no return type? This is where the delegate Action comes in:
Code:
    public static void Main(String[] args)
    {
        Action<int, int, int> printSumAndAverage = (int a, int b, int c) =>
        {
            Console.WriteLine("Sum = " + a + b + c);
            Console.WriteLine("Average = " + (a + b + c) / 3);
        };
        printSumAndAverage(1, 2, 3);
        printSumAndAverage(2, 3, 4);
        printSumAndAverage(22, 13, 64);
    }

Now you may say that it doesn't really make much difference if you just stick with declaring methods and using them.
But one advantage that that delegates has over usual methods is that you can pass the delegates as an argument to a parameter.
LINQ Lambdas makes extensive uses of these delegates. For example,
Code:
    public static void Main(String[] args)
    {
        List<int> numbers = new List<int>();

        Random rng = new Random();
        for (int i = 0; i < 10000; numbers.Add(rng.Next()), i++) ;

        numbers.RemoveAll((int x) => x % 2 == 0);
        // Everytime the list iterates into another element, the element is passed into the delegate as the parameter x
        // If the lambda expression used for the delegate evaluates to true (I.E. x is even), then the element is removed.

        numbers.ForEach((int x) => x += 5);
        // Everytime the list iterates into another element, the element is passed BY REFERENCE to the delegate as parameter x
        // The lambda expression then adds 5 to the REFERENCE of the element, which is the same as adding 5 to the element itslef

        Console.WriteLine(numbers.Count((int x) => x % 3 == 9));
        // Everytime the list iterates into another element, the element is passed to the delegate as parameter x
        // If the lambda expression used for the delegate evaluates to true (I.E. x is divisible by 3), then the count increments by one.

        foreach (int match in numbers.Where((int x) => x % 5 == 0))
        {
            // Everytime the list iterates into another element, the element is passed to the delegate as parameter x
            // If the lambda expression used for the delegate evaluates to true (I.E. x is divisible by 5), it assigns the element to the variable "match"
            // and does whatever is inside this foreach block.
        }

    }
 
Last edited:
Trust your senses
Joined
Sep 12, 2009
Messages
661
Reaction score
173
Jash - C# Language features/tips/tricks - RaGEZONE Forums


Quite some useful tips :)
 
Developer
Loyal Member
Joined
Jul 28, 2009
Messages
983
Reaction score
133
This helped me a lot, please make more of this kind of tutorials!
 
• ♠️​ ♦️ ♣️ ​♥️ •
Joined
Mar 25, 2012
Messages
909
Reaction score
464
-> Your first 2 property topic examples are not exactly correct. Just the fact a public key has a get/set operator and a private field to set its value to makes the public field to a property.

A property is a member that provides a flexible mechanism to read, write, or compute the value of a private field.


-> About var: Nobody should be too lazy to add any namespace! While any (class) type in front of your variable is an explicit type, using var in front of a variable is an implicit type. An implicit type allows the compiler to set it's type in run time. I approve this is more for lazy people. It should be avoided, however it's still safer than dynamic-keyword.

-> I like the topic about Aliases, here I learned something new.

-> Generics: In the third code example the line in the contructor should not be this.array = new object[size];. It should be this.array = new T[size];. You should even talk about Generic Constraints: . After that I would even explain why you do not need any constraint for arrays (hail corner brackets ).

-> You misunderstood the default key word in any ways. Default allows to get the default value of any type. This is necessary when using generics and not knowing it's a primitive value type or an constructing reference type. It will return NULL on reference types as well as it will return 0 for value types. (

-> I will check out Async/Await and Delegates and Lambdas expressions later.

-> You got everything two times in your tutorial.


Sincerely, VibeTribe.
 
Last edited:
Newbie Spellweaver
Joined
Oct 17, 2013
Messages
71
Reaction score
43
Great Tutorial, I even learned something new from the section on null-coalescing operator!

On the topic of Properties you can shorthand it so you do not have to create a private field also a property to manipulate that field.
PHP:
private String name;
public String Name
{
    get: { return name; }
    set: { name = value; }
}
can be shorthanded to
PHP:
public String Name { get; set; }

Some information that I feel should be listed under the Property section is that they not only allow your do something special during the get / set operations such as validation like you mentioned, but a field being a Property is required for Bindings in WPF.


I disagree with VibeTribe in regards to use of the "var" keyword. It is all about your own personal style but I feel that the brevity of your code is vital when it comes to readability and speed. Using var will save you on many keystrokes throughout your day and greatly improve code readability in situations where the type is easily known.

There are times where I would advise against using var, such as any place where you, as the reader, cannot quickly infer the type of the variable from it's usage. In that case, then you should declare the variable explicitly so that whomever reads the code can understand it easier and quickly.



On the Lambdas section the compiler can also infer the type to shorten your expressions down even more.

take the line from your example:
PHP:
numbers.ForEach((int x) => x += 5);
you get the same result from:
PHP:
numbers.ForEach(x => x += 5);


There are several things I could think of that would be a good include to this article, but I'll just start with 1 that will logically follow your section on Lambdas and will help improve performance of those calculations.

Using the Parallel Class. Whenever you have large collections of data you are looping through you can improve your performance by switching from a For or a ForEach to a Parallel.For or Parallel.ForEach. It is important to note that Parallel class does not guarantee that it will always run in parallel with multiple threads, but most likely will if/when it can.

These functions can be written using Parallel like so:
PHP:
numbers.ForEach(x => x+=5);

becomes

Parallel.ForEach(numbers, x => x+=5);

and

for(var i = 0; i < numbers.Count; i++)
{
    numbers[i] += 5;
}

becomes

Parallel.For(0, numbers.Count, i => numbers[i] += 5);

Lastly, I would like to note that whenever possibly use a For loop over a ForEach loop. Using a ForEach loop in C# creates extra temporary objects that will be sent to the garbage collector and impede performance.
 
Initiate Mage
Joined
Jan 8, 2014
Messages
2
Reaction score
0
I would like to see some C# threading, hooking, and dll injection. I guess this is a request(?)
 
Back
Top