
17. LINQ, Regex, Memory Management, Garbage Collector
LINQ to SQL
LINQ (Language Integrated Query) provides a unified query syntax to retrieve and manipulate data from various sources, including collections, XML documents, and SQL databases.
- LINQ to SQL is specifically designed for querying and updating SQL Server databases.
- It maps database tables to C# classes and translates LINQ expressions into SQL commands.
- This often results in simpler code compared to raw ADO.NET queries.
- One limitation is its focus on SQL Server; if you need to support other databases, consider Entity Framework or other providers.
Basic Example
using (var context = new DataContext("your_connection_string"))
{
Table<Customer> customers = context.GetTable<Customer>();
var query = from c in customers
where c.City == "London"
select c;
foreach (var customer in query)
{
Console.WriteLine(customer.Name);
}
}
Regular Expressions (Regex)
Regular expressions are patterns used to match or validate strings, such as checking an email or phone number format. In C#, you can use the System.Text.RegularExpressions.Regex
class to define and apply these patterns.
using System.Text.RegularExpressions;
bool IsValidEmail(string email)
{
string pattern = @"^[^@\s]+@[^@\s]+\.[^@\s]+$";
return Regex.IsMatch(email, pattern);
}
Memory Management in C#
Managed vs. Unmanaged Heap
- Managed Heap
- Managed by the CLI (Common Language Infrastructure) or .NET runtime.
- When you create an object (
new SomeClass()
), memory is allocated on the managed heap.
- The .NET Garbage Collector (GC) eventually frees unused objects automatically.
- Uses a Next Object Pointer to keep track of the next free address, which allows fast allocations.
- Unmanaged Heap
- Managed manually with pointers.
- Typically used with
unsafe
code blocks, or for interop with native libraries.
- Not automatically garbage-collected.
Generations and the Garbage Collector
.NET GC employs a generational approach. Objects are categorized into Generations (0, 1, 2) depending on their lifespan:
- Gen 0: Newly allocated objects (often short-lived).
- Gen 1: Surviving objects from Gen 0.
- Gen 2: Surviving objects from Gen 1 (long-lived objects).
When Gen 0 becomes full, the GC runs to reclaim memory. Short-lived objects are freed, and survivors move to Gen 1. Similarly, long-lived objects can move to Gen 2. This approach is efficient because most objects die young, so collecting Gen 0 frequently is relatively cheap.
GC Process
- Allocation: Creating new objects places them in Gen 0.
- Threshold Reached: When Gen 0 is full, GC triggers a collection.
- Mark and Compact: GC marks reachable objects and compacts memory by moving surviving objects together (defragmentation).
- Promotion: Surviving Gen 0 objects move to Gen 1; surviving Gen 1 objects move to Gen 2.
- Gen 2 collections happen less frequently, as these objects are assumed to be long-lived.
Finalizers vs. IDisposable
- Finalizer (
~ClassName()
)- Called by the GC before reclaiming the object’s memory.
- Expensive because the GC has to run twice on objects with finalizers (once to identify them, another to finalize).
- Should be avoided if possible.
- IDisposable / Dispose
- A more efficient pattern for releasing resources (e.g., file handles, database connections) deterministically.
- Typically combined with a
using
statement for automatic disposal.
public class ResourceHolder : IDisposable
{
// Acquire resources here
public void Dispose()
{
// Release unmanaged resources here
GC.SuppressFinalize(this); // Prevent finalizer call
}
}
Using IDisposable
and using
is often preferred over relying on finalizers:
using (var holder = new ResourceHolder())
{
// Work with resource
} // Dispose is automatically called here
References
The content in this document is based on the original notes provided in Azerbaijani. For further details, you can refer to the original document using the following link:
Original Note - Azerbaijani Version