Expression Trees

  • ‘tree like’ data structure
  • each node is expression (method call, equality comparison, binary operation etc.) representing a piece of code
  • you can compile expression tree and run code it represent
  • enables dynamic code generation at runtime
  • LINQ queries on DBs are implemented with Expression Trees
  • used in the dynamic language runtime (DLR)
  • anonymous lambda expression can be converted to ExpressionTree via compiler (i.e. x => x*2 can be represented as tree instead of delegate or anonymous lambda function)

Further read:

https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/expression-trees/

Linq

  • consistent model for working with data from various kinds of sources and formats (XML, SQL, ADO.NET, Datasets, .NET collections etc)
  • 3 stages of working with LINQ:
    • obtain data source
    • create the query
    • execute the query
  • data sources implements IEnumerable<> and are called queryable types
  • IQueryable<> interface inherits from IEnumerable<>
  • generally it is better to use LINQ via IQueryable<> which produces deferred query instead of producing result immediately
  • queries can be executed multiple times
  • queries can be forced immediate execution via Count(), Max(), ToList() or ToArray() etc.
  • LINQ to DB libraries (like EntityFramework) usually are implemented via Expression Trees

Entity Framework: eager and lazy loading

  • lazy loading:
    • delaying load of data until we specifically request for it
    • i.e. accessing customer.Address loads Address of a customer in the background via separate SQL query
    • property needs to be public, virtual
    • context.Configuration.ProxyCreationEnabled should be true
    • context.Configuration.LazyLoadingEnabled should be true
    • to disable lazy loading completely Context.Configuration.LazyLoadingEnabled = false;
  • eager loading
    • opposite of lazy loading
    • loads related entities as part of the query
    • done via .Include() query

Further read:

https://www.entityframeworktutorial.net/lazyloading-in-entity-framework.aspx

https://www.entityframeworktutorial.net/eager-loading-in-entity-framework.aspx

Pattern matching

Pattern matching is used for:

  • testing expression to check if some value have certain characteristics
  • safer compare because ‘==’ and ‘!=’ can be overloaded

Examples:

a is int number
sequence is IList<T> list

switch statement:

command switch
{
   Operation.SystemTest => RunDiagnostics(),
   Operation.Start => StartSystem(),
   Operation.Stop => StopSystem(),
   Operation.Reset => ResetToReady(),
   _ => throw new ArgumentException("Invalid enum value for command", nameof(command)),
};

switch with ranges:

tempInFahrenheit switch
{
    (> 32) and (< 212) => "liquid",
    < 32 => "solid",
    > 212 => "gas",
    32 => "solid/liquid transition",
    212 => "liquid / gas transition",
};

collection pattern matching:

array is [1,1,2,3,5,8, ..]

Further read:

https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/functional/pattern-matching