Extension Methods, Lambda Expressions and LINQ
Telerik Academy Alpha

 

 Table of contents

Extension methods

 What are extension methods?

  • Once a type is defined and compiled into an assembly its definition is, more or less, final
    • The only way to update, remove or add new members is to re-code and recompile the code
  • Extension methods allow existing compiled types to gain new functionality
    • Without recompilation
    • Without touching the original assembly

 Defining Extension Methods

  • Extension methods
    • Defined in a static class
    • Defined as static
    • Use the this keyword before its first argument to specify the class to be extended
  • Extension methods are "attached" to the extended class
    • Can also be called statically through the defining static class

 Extension Methods – Examples

 Extension Methods – Examples

Anonymous Types

 Anonymous Types

  • Anonymous types
    • Encapsulate a set of read-only properties and their value into a single object
    • No need to explicitly define a type first
  • To define an anonymous type
    • Use of the var keyword in conjunction with the object initialization syntax
var point = new { X = 3, Y = 5 };

 Anonymous Types - Example

  • At compile time, the C# compiler will autogenerate an uniquely named class
  • The class name is not visible from C#
    • Using implicit typing (var keyword) is mandatory
var myCar = new { Color = "Red", Brand = "Tesla", TopSpeed = 270 };
Console.WriteLine("My car is a {0} {1}.", myCar.Color, myCar.Brand);
  • Use an anonymous type to represent a car:

 Anonymous Types - Properties

var p = new { X = 3, Y = 5 };
var q = new { X = 3, Y = 5 };

Console.WriteLine(p == q); // false
Console.WriteLine(p.Equals(q)); // true
  • Anonymous types are reference types directly derived from System.Object
  • Have overridden version of Equals(), GetHashCode(), and ToString()
    • Do not have == and != operators overloaded

 Anonymous Types - Properties

var arr = new[]
{
    new { X = 3, Y = 5 },
    new { X = 1, Y = 2 },
    new { X = 0, Y = 7 }
};

foreach (var item in arr)
{
    Console.WriteLine("({0}, {1})", item.X, item.Y);
}
  • You can define and use arrays of anonymous types through the following syntax:

Delegates

 What are Delegates?

  • Delegates are special .NET types that hold a method reference
  • Describe the signature of given method
    • Number and types of the parameters
    • The return type
  • Their "values" are methods
    • These methods match their signature (parameters and return types)
    • Delegates are reference types

 What are Delegates?

  • Delegates are roughly similar to function pointers in C++
    • Strongly-typed pointer (reference) to a method
    • Pointer (address) to a callback function
  • Can point to static and instance methods
  • Can point to a sequence of multiple methods
    • Known as multicast delegates
  • Used to perform callback invocations
  • Implement the "publish-subscribe" model

 Delegates - Example

 Generic Delegates

  • A delegate can be generic:
public delegate void SomeDelegate<T>(T item);
  • Using a generic delegate:
public static void Notify(int i) { … }
SomeDelegate<int> d = new SomeDelegate<int>(Notify);
  • The above can simplified as follows:
SomeDelegate<int> d = Notify;

 Multicast Generic Delegates - Example

 Predefined Delegates

  • Predefined delegates in .NET:
    • Action<T1,T2> - generic predefined void delegate with parameters of types T1 and T2.
    • Func<T1,T2,TResult> - generic predefined delegate with return value of type TResult
    • Both overloads can accept from 1 to 16 parameter of Tn types.
Func<string, int> predefinedIntParse = int.Parse;
int number = predefinedIntParse("50");

Action<object> predefinedAction = Console.WriteLine;
predefinedAction(1000);

Events

 What are Events?

  • A message sent by an object to signal the occurrence of an action
  • Enable a class or object to notify other classes or objects when something of interest occurs
    • Publisher – the class that sends/raises the event
      • ​Doesn’t know which object/method will handle the event
    • Subscribers – the classes that receive/handle the event
  • In .NET, events are based on the EventHandler delegate and the EventArgs base class

 Define Events

  • Use the event keyword
  • Specify type of delegate for the event – EventHandler
  • Add a protected virtual method
    • Name the method On[EventName]
class Counter {
  public event EventHandler ThresholdReached;

  protected virtual void OnThresholdReached(EventArgs e) {
    if (this.ThresholdReached != null) {
        this.ThresholdReached(this, e);
    }
  }
}

 Event Data

  • Data that is associated with an event can be provided through an event data class
  • EventArgs class is the base type for all event data classes
    • Also used when an event does not have any data associated with it
    • Naming of the data class – [Name]EventArgs
public class ThresholdReachedEventArgs : EventArgs
{
  public int Threshold { get; set; }
  public DateTime TimeReached { get; set; }
}

 Event Handlers

  • To respond to an event, you define an event handler method
    • Must match the signature of the delegate
class Example {
  static void Main() {
    Counter counter = new Counter();
    counter.ThresholdReached += CounterThresholdReached;
  }

  static void CounterThresholdReached(object sender, EventArgs e) {
    Console.WriteLine("The threshold was reached.");
  }
}

Lambda Expressions

 What are Lambda Expressions?

  • A lambda expression is an anonymous function containing expressions and statements
    • Used to create delegates or expression tree types
  • Lambda expressions
    • Use the lambda operator =>
      • Read as "goes to"
    • The left side specifies the input parameters
    • The right side holds the expression or statement

 Lambda Expressions - Example

 Lambda Expressions - Example Sorting

 Delegates Holding Lambda Functions

  • Lambda functions can be stored in variables of type delegate
    • Delegates are typed references to functions
  • Standard function delegates in .NET:
    • Func<TResult>, Func<T,TResult>, Func<T1,T2,TResult>
Func<bool> boolFunc = () => true;
Func<int, bool> intFunc = (x) => x < 10;

if (boolFunc() && intFunc(5)) 
{
  Console.WriteLine("5 < 10");
}

 Predicates

  • Predicates are predefined delegates with the following signature:
public delegate bool Predicate <T>(T obj)
  • Define a way to check if an object meets some Boolean criteria
  • Similar to Func<T,bool>
  • Used by many methods of Array and List<T> to search for an element
    • For example List<T>.FindAll(…) retrieves all elements meeting the criteria

 Predicates - Example

 Action<T> and Func<T>

  • Action<T> - void delegate with parameter T
  • Func<T, Result> - result delegate returning Result
Action<int> act = (number) =>
{
   Console.WrileLine(number);
}

act(10); // logs 10

Func<string, int, string> greet = (name, age) =>
{
   return "Name: " + name + "Age: " + age;
}

Console.WriteLine(greet("Ivaylo", 10));

LINQ and Query Keywords

 What is LINQ?

  • LINQ is a set of extensions to .NET Framework
    • Encompasses language-integrated query, set, and transform operations
    • Consistent manner to obtain and manipulate "data" in the broad sense of the term
  • Query expressions can be defined directly within the C# programming language
    • Used to interact with numerous data types
    • Converted to expression trees at compile time and evaluated at runtime

 LINQ and Query Keywords

  • Language Integrated Query (LINQ) query keywords
    • from – specifies data source and range variable
    • where – filters source elements
    • select – specifies the type and shape that the elements in the returned sequence
    • group – groups query results according to a specified key value
    • orderby – sorts query results in ascending or descending order

 LINQ Query Examples

 LINQ Query Examples - Nested Queries

 LINQ Query Examples - Orderby

 Fluid API Operations

  • .Where()
    • Searches by given condition
  • .First() / .FirstOrDefault()
    • Gets the first matched element
  • .Last() / .LastOrDefault()
    • Gets the last matched element
  • .Select() / .Cast()
    • Makes projection (conversion) to another type
  • .OrderBy() / .ThenBy() / .OrderByDescending()
    • Orders a collection

 Fluid API Operations

  • .Any()
    • Checks if any element matches a condition
  • .All()
    • Checks if all element matches a condition
  • .ToArray() / .ToList() / .AsEnumerable()
    • Converts the collection type
  • .Reverse()
    • Reverses a collection

 LINQ Query Examples - Fluid API VS Query

 Querying Arrays

  • Any kind of arrays can be used with LINQ
    • Can be even an untyped array of objects
    • Queries can be applied to arrays of custom objects
Book[] books = {
   new Book { Title="LINQ in Action" },
   new Book { Title="Extreme LINQ" } };

var titles = books
   .Where(book => book.Title.Contains("Action"))
   .Select(book => book.Title);

var titles = b in books
   where b.Title.Contains("Action")
   select b.Title;

 Querying Generic Lists

  • The previous example can be adapted to work with a generic list
    • List<T>, Queue<T>, Stack<T>, HashSet<T>, etc.
List<Book> books = new List<Book>() {
   new Book { Title="LINQ in Action" },
   new Book { Title="Extreme LINQ" } };

var titles = books
   .Where(book => book.Title.Contains("Action"))
   .Select(book => book.Title);

 Querying Strings

  • Although System.String may not be perceived as a collection at first sight
    • It actually is a collection, because it implements IEnumerable<char>
var count = "Non-letter characters in this string: 8"
  .Where(c => !Char.IsLetter(c))
  .Count();

var count = c in "Non-letter characters in this string: 8"
  where !Char.IsLetter(c)
  select c.Count();

Console.WriteLine(count); // 8

 Fluid API Aggregation Methods

  • .Average()
    • Calculates the average value of a collection
  • .Count()
    • Counts the elements in a collection
  • .Max()
    • Determines the maximum value in a collection
  • .Sum()
    • Sums the values in a collection

 Aggregation Methods - Examples

double[] temperatures = { 28.0, 19.5, 32.3, 33.6, 26.5, 29.7 };

var highTempCount = temperatures.Count(p => p > 30);

var highTempCount =
  (from p in temperatures
   where p > 30
   select p).Count();

Console.WriteLine(highTempCount); // 2

 Aggregation Methods - Examples

double[] temperatures = { 28.0, 19.5, 32.3, 33.6, 26.5, 29.7 };

var maxTemp = temperatures.Max();

var maxTemp =
  (from p in temperatures
   select p).Max();

Console.WriteLine(maxTemp); // 33.6

Questions?

[C# OOP] Extension Methods, Lambda Expressions and LINQ

By telerikacademy

[C# OOP] Extension Methods, Lambda Expressions and LINQ

  • 2,092