Skip to content

masseydigital/csharp-advanced-topics-course

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 

Repository files navigation

csharp-advanced-topics-course

This is a learning repo for C# Advanced Topics Udemy course.

LINQ - Language Integrated Query

LINQ is a .net library that allows a programmer to write code which queries collections in a similar manner to SQL.

There are three basic operations:

  1. Get the Source
  2. Create the Query
  3. Execute the Query

The anatomy of a Query is:

  1. Define the source - from ... in ...
  2. Define some conditions - where ...
  3. Take the filtered output - select ...
    using System.Collections.Generic;
    using System.Linq;

    string sentence = "I love cats";
    string[] catNames = {"Lucky", "Bella", "Luna", "Oreo", "Simba", "Toby", "Loki" };
    int[] numbers = {5, 6, 12, 34, 99, 106, 23, 5, 7, 17, 9, 54, 35, 28}

    var getNumbers =    from number in numbers
                        where number < 5
                        orderby number
                        select number;

    var getCatsWithA =  from cat in catNames
                        where cat.Contains("a")
                        where cat.Length < 5
                        select cat;

    System.Console.WriteLine(string.Join(", ", getNumbers));
    System.Console.WriteLine(string.Join(", ", getCatsWithA));

Queries with LINQ are only run when the collection is used somewhere

Multiple where classes can be used for multiple checked conditions.

The orderby keyword can be used to order the elemnts in the query. Multiple orderby clauses can be used for elements with similar properties.

The descending keyword can be used to perform less than to greater than ordering. The ascending keyword can be used to perform the opposite functionality.

Lambda Expressions

Lambda expressions are used to do some operation on an input. They are used in the place of methods when the body is short and they are not used a lot. LINQ operations are perfect for utilizing lambda expressions. Lambda Operator: => (Input) => Work on the Input i.e. N => ((N%2)==1);

The input does not need to explicitly state its type, but you can add it along with surrounding parenthesis to make it explicit. You can also have multiple input types that can be defined with parenthesis, as well as no inputs in the case of Actions.

    using System.Collections.Generic;
    using System.Linq;
    
    int[] numbers = {5, 6, 12, 34, 99, 106, 23, 5, 7, 17, 9, 54, 35, 28}
    string[] catNames = {"Lucky", "Bella", "Luna", "Oreo", "Simba", "Toby", "Loki" };
    object[] mix = {1, "string", 'd', new List<int>(){1,2,3,4}, "dd", 's', 1, 5, 3};
    List<Warrior> warriros = new List<Warrior>()
    {
        new Warrior(){ Height = 100 },
        new Warrior(){ Height = 125 },
        new Warrior(){ Height = 115 },
        new Warrior(){ Height = 120 },
        new Warrior(){ Height = 100 }
    }

    var oddNumbers = from n in numbers
                     where n % == 1
                     select n;
    
    var lambdaOddNumbers = numbers.Where(n => (n % 2 == 1));

    System.Console.WriteLine(string.Join(", ", oddNumbers));
    System.Console.WriteLine(string.Join(", ", lambdaOddNumbers));

    // math functions such as .Average can be used in conjunction with lamda expressions
    double average = catNames.Average(cat => cat.Length);
    System.Console.WriteLine(average);

    // .OfType can be used to call out a specific type
    var allIntegers = mix.OfType<int>().Where(i => i < 3);
    System.Console.WriteLine(string.Join(", ", allIntegers));

    // .Select will return a collection of heights that meet the lambda criteria
    var shortWarriors = warriors.Where(wh => wh.Height == 100)
                                .Select(wh => (wh.Height));

    // .ForEach can be used to print out items with a single line of code
    warriors.ForEach(w => Console.WriteLine(w.Height));

Extension Methods

Extension methods allow you to extend the functionality of a type by adding a .Method() to the type.

The this keyword in the method parameters makes the method an extension method.

Extension method generally live in their own class.

Generics

Generics are methods, classes, variables that can apply to more than one type. You can use them to create methods which apply to more common functionality that different types might have, i.e. comparing two ints, strings, objects, etc.

T is an accepted type name for generics.

The IComparable interface can be used in conjunction with the where keyword to make a generic method have the ability to use the CompareTo extension method.

List is an example of where generic types are used.

The dynamic keyword allows you to provide runtime type checking instead of having to check at compile time.

Delegates

Delegates are methods as variables. Methods that use a delegate must have the same signature.

Delegates can be chained together to perform more complex operations.

func is a built-in delegate type that allows you to pass in inputs and have an output into a single line.

Action is another built-in delegate type. Actions only take inputs (no return types, void).

Anonymous Methods allow you to define more complex delegate (actions/funcs) behavior using a lambda expression. You can chain anonymous methods by calling anonymous methods within anonymous methods.

Events

Events enable a class or object to notify other classes or objects when something of interest occurs. Events follow the publisher-subscriber model where the sending class is called the publisher and the receiving class is called the subscriber.

Anatomy of an event:

  1. Delegate matching the Event signature
  2. Event of the same type as the Delegate
  3. Raise the Event at some point

Best practice is to use the suffix, Handler, for delegates associated with events.

With events, we can use the EventHandler to replace the delegate keyword. You can pass event args with EventHandler by using triangle brackets to pass in the args object.

You can put a ? at the end of event to check if it has subscribers before firing the event. This replaces the if(event != null) code.

Asynchronous Programming

Asynchronous programming allows you to perform actions in their own threads or running loops without interrupting the normal flow of an application, i.e. databased querying, authentication, etc.

The Task class from System.Threading.Tasks can be used to define a piece of code you want to thread. To use tasks, you pass in a method which has no inputs and is void.

.Start starts the task, .Wait waits for the task to finish before continuing.

You can also use Task.Factory to create tasks. When you do this, you no longer need .Start method.

You can also use Task.Run with an Action to create tasks.

You can use anonymous methods to pass in parameters into the function.

You can get a return from a Task by using triangle brackets and the type. The Result property in the Task class gives you the return.

The async keyword can be used to make a method asynchronous. Async methods must be void.

It is best practice to end async methods with Async suffix.

About

This is a learning repo for C# Advanced Topics Udemy course.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages