LINQ, lambda, expression Trees, extension methods, auto properties, anonymous method

 

1. LINQ (Language Integrated Query)

LINQ is a powerful feature in C# that provides a query syntax similar to SQL for querying various data sources such as in-memory collections, databases, XML, etc. It can be used with collections like arrays, lists, and databases like Entity Framework.

Example: LINQ with In-Memory Collections

using System; using System.Linq; using System.Collections.Generic; class Program { static void Main() { List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; // LINQ query to find even numbers var evenNumbers = from num in numbers where num % 2 == 0 select num; foreach (var number in evenNumbers) { Console.WriteLine(number); // Output: 2, 4, 6, 8, 10 } } }

In this example, LINQ is used to filter even numbers from a list.

2. Lambda Expressions

Lambda expressions are concise, inline functions used primarily with LINQ queries and delegates. They are a shorthand syntax for anonymous methods.

Example: Lambda Expression in LINQ

class Program { static void Main() { List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; // Lambda expression for filtering even numbers var evenNumbers = numbers.Where(n => n % 2 == 0); foreach (var number in evenNumbers) { Console.WriteLine(number); // Output: 2, 4, 6, 8, 10 } } }

Here, n => n % 2 == 0 is a lambda expression used to filter even numbers.

3. Expression Trees

Expression trees represent code in a tree-like data structure, where each node is an expression (e.g., method call, binary operation). Expression trees are useful in scenarios like LINQ to SQL, where queries need to be translated to another language (e.g., SQL).

Example: Expression Trees

using System; using System.Linq.Expressions; class Program { static void Main() { // Define an expression tree for a lambda expression Expression<Func<int, bool>> expr = num => num > 5; // Decompose and inspect the expression tree Console.WriteLine($"Expression: {expr}"); Console.WriteLine($"Body: {expr.Body}"); Console.WriteLine($"Parameters: {string.Join(", ", expr.Parameters)}"); } }

The output will show the structure of the expression tree, which can later be compiled or manipulated programmatically.

4. Extension Methods

Extension methods allow you to add methods to existing types without modifying the original type or using inheritance. They are defined as static methods in static classes but behave like instance methods.

Example: Extension Method

public static class StringExtensions { // Extension method for the string type public static bool IsUpperCase(this string str) { return str == str.ToUpper(); } } class Program { static void Main() { string myString = "HELLO"; // Using the extension method bool isUpper = myString.IsUpperCase(); Console.WriteLine(isUpper); // Output: True } }

The IsUpperCase method extends the string class and can be used like an instance method.

5. Anonymous Types

Anonymous types allow you to create objects without explicitly defining a class. They are useful for holding a set of properties in a concise manner, often in LINQ queries.

Example: Anonymous Types

class Program { static void Main() { var person = new { Name = "John", Age = 30 }; Console.WriteLine($"Name: {person.Name}, Age: {person.Age}"); // Output: Name: John, Age: 30 } }

Anonymous types are often used to quickly encapsulate data in LINQ queries or when working with data transformations.

6. Automatic Properties

Automatic properties simplify the declaration of properties by allowing the compiler to generate the backing field. You just need to declare the property, and the getter and setter are automatically handled.

Example: Automatic Properties

public class Person { // Automatic properties public string Name { get; set; } public int Age { get; set; } } class Program { static void Main() { Person person = new Person { Name = "Alice", Age = 25 }; Console.WriteLine($"Name: {person.Name}, Age: {person.Age}"); // Output: Name: Alice, Age: 25 } }

Automatic properties reduce boilerplate code and simplify class declarations.

7. Object and Collection Initializers

Object initializers allow you to set properties during object creation, and collection initializers allow you to add elements to a collection when it's created. This can all be done in a single expression.

Example: Object and Collection Initializers

class Program { static void Main() { // Object initializer var person = new Person { Name = "Bob", Age = 35 }; // Collection initializer var numbers = new List<int> { 1, 2, 3, 4, 5 }; Console.WriteLine($"Name: {person.Name}, Age: {person.Age}"); // Output: Name: Bob, Age: 35 Console.WriteLine(string.Join(", ", numbers)); // Output: 1, 2, 3, 4, 5 } } public class Person { public string Name { get; set; } public int Age { get; set; } }

These initializers make the code more concise and readable.

8. Query Expressions

Query expressions provide a declarative, SQL-like syntax for LINQ queries. They are often used for complex queries because they are more readable and intuitive.

Example: Query Expression

using System; using System.Linq; using System.Collections.Generic; class Program { static void Main() { List<Person> people = new List<Person> { new Person { Name = "Alice", Age = 30 }, new Person { Name = "Bob", Age = 25 }, new Person { Name = "Charlie", Age = 35 } }; // Query expression syntax (similar to SQL) var query = from p in people where p.Age > 25 select p; foreach (var person in query) { Console.WriteLine($"{person.Name} is {person.Age} years old."); } } } public class Person { public string Name { get; set; } public int Age { get; set; } }

In this example, the query expression syntax (from, where, select) filters the list of people based on their age.

Summary of Key Points

  1. LINQ provides SQL-like query capabilities for querying in-memory collections, databases, XML, and more.
  2. Lambda expressions offer a concise way to define inline methods, often used in LINQ queries.
  3. Expression trees represent code as data structures, useful for scenarios like LINQ to SQL, where code needs to be translated.
  4. Extension methods allow you to add methods to existing types without modifying them or using inheritance.
  5. Anonymous types enable quick object creation without explicit class definitions, useful for temporary data containers.
  6. Automatic properties streamline property declarations, letting the compiler handle the underlying storage.
  7. Object and collection initializers provide a concise way to initialize objects and collections during creation.
  8. Query expressions offer a declarative, SQL-like syntax for LINQ queries, making them more readable and powerful for complex data queries.

Post a Comment