Every essential C# and .NET Core concept in one place — syntax, OOP, LINQ, async/await, generics, dependency injection, Entity Framework, testing and more.
C# is a statically-typed language. Understand value types, reference types, nullable types and modern expression syntax.
// Value types int age = 30; double pi = 3.14159; float temp = 36.6f; decimal price = 19.99m; bool active = true; char grade = 'A'; // Reference types string name = "Alice"; object obj = new Object(); // Implicit typing var count = 10; // int var msg = "hello"; // string // Nullable types int? nullInt = null; string? nullStr = null; // Null-coalescing operators var val = nullInt ?? 0; nullStr ??= "default";
// Switch expression (C# 8+) var result = score switch { >= 90 => "A", >= 80 => "B", >= 70 => "C", _ => "F" }; // Pattern matching if (obj is string s && s.Length > 5) Console.WriteLine(s.ToUpper()); // foreach loop foreach (var item in items) Console.WriteLine(item); // for / while / do-while for (int i=0; i<10; i++) { } while (condition) { } do { } while (condition);
// String interpolation var msg = $"Hello, {name}! Age: {age}"; // Verbatim string (raw path) var path = @"C:\Users\Alice\docs"; // Raw string literal (C# 11+) var json = """ { "name": "Alice" } """; // Common methods name.ToUpper(); name.ToLower(); name.Trim(); name.Contains("Alice"); name.Replace("a", "@"); name.Split(','); string.Join(", ", items); // StringBuilder (mutable) var sb = new StringBuilder(); sb.Append("Hello"); sb.AppendLine(" World");
| Alias | .NET Type | Size | Range / Notes |
|---|---|---|---|
int |
System.Int32 |
32-bit | −2,147,483,648 to 2,147,483,647 |
long |
System.Int64 |
64-bit | ±9.2 × 10¹⁸ |
double |
System.Double |
64-bit | ~15-17 significant digits |
decimal |
System.Decimal |
128-bit | 28-29 digits, ideal for money |
bool |
System.Boolean |
8-bit | true / false |
char |
System.Char |
16-bit | Unicode character |
string |
System.String |
ref type | Immutable sequence of chars |
object |
System.Object |
ref type | Root of all C# types |
Master classes, records, interfaces, inheritance, polymorphism, encapsulation and access modifiers in C#.
public class Person { // Auto-properties public string Name { get; set; } = ""; public int Age { get; init; } public string Email { get; private set; } = ""; // Primary constructor (C# 12) public Person(string name, int age) { Name = name; Age = age; } // Method public string Greet() => $"Hi, I'm {Name}, aged {Age}"; } // Record — immutable by default public record Product( string Name, decimal Price ); // With-expression (non-destructive) var p1 = new Product("Pen", 1.99m); var p2 = p1 with { Price = 2.49m };
// Interface public interface IAnimal { string Name { get; } void Speak(); // Default impl (C# 8+) string Describe() => $"I am {Name}"; } // Abstract base class public abstract class Animal : IAnimal { public string Name { get; } protected Animal(string name) => Name=name; public abstract void Speak(); } // Concrete class public sealed class Dog : Animal { public Dog(string name) : base(name) {} public override void Speak() => Console.WriteLine("Woof!"); } // Polymorphism IAnimal a = new Dog("Rex"); a.Speak(); // Woof!
| Modifier | Visibility |
|---|---|
public |
Anywhere |
private |
Same class only |
protected |
Class + derived classes |
internal |
Same assembly |
protected internal |
Assembly or derived |
private protected |
Same assembly + derived |
// Enum public enum Status { Active, Inactive, Pending } Status s = Status.Active; // Struct (value type) public struct Point { public int X, Y; } // Static class public static class MathHelper { public static int Square(int n) => n*n; }
Arrays, Lists, Dictionaries, HashSets, Stacks, Queues and immutable collections from the .NET BCL.
// Array int[] nums = { 1, 2, 3, 4, 5 }; int[] arr = new int[10]; var len = nums.Length; // List<T> var list = new List<string> { "apple", "banana" }; list.Add("cherry"); list.Remove("banana"); list.Contains("apple"); // true list.Count; list.Sort(); list.Reverse(); // Collection expressions (C# 12) List<int> nums2 = [1, 2, 3]; int[] arr2 = [4, 5, 6];
// Dictionary<TKey,TVal> var dict = new Dictionary<string,int> { { "Alice", 30 }, { "Bob", 25 } }; dict["Charlie"] = 28; // add/update dict.TryGetValue("Alice", out int age); // safe get dict.ContainsKey("Bob"); // true dict.Remove("Bob"); // Iterate foreach (var (k,v) in dict) Console.WriteLine($"{k}={v}"); // HashSet<T> var set = new HashSet<int> { 1, 2, 3 }; set.Add(4); set.UnionWith(new[] {3,4,5}); set.IntersectWith(new[] {2,3});
// Queue (FIFO) var q = new Queue<string>(); q.Enqueue("first"); q.Enqueue("second"); var item = q.Dequeue(); // "first" q.Peek(); // "second" // Stack (LIFO) var stk = new Stack<int>(); stk.Push(1); stk.Push(2); var top = stk.Pop(); // 2 // Span<T> — zero-alloc slice int[] data = [1,2,3,4,5]; Span<int> slice = data.AsSpan(1,3); // [2,3,4] — no allocation
Query any IEnumerable<T> with method syntax or query expressions. Deferred execution and lazy evaluation explained.
var nums = new[] { 3,1,4,1,5,9,2 }; // Filter + sort + project var result = nums .Where(n => n > 3) .OrderBy(n => n) .Select(n => n * 2) .ToList(); // [8,10,18] // Aggregates nums.Sum(); // 25 nums.Average(); // 3.57 nums.Min(); nums.Max(); nums.Count(n => n > 3); // 3 // First / Single / Any / All nums.First(n => n>4); nums.FirstOrDefault(n => n>10); nums.Any(n => n>8); nums.All(n => n>0);
// GroupBy var grouped = people .GroupBy(p => p.Department) .Select(g => new { g.Key, Count = g.Count(), AvgAge = g.Average(p=>p.Age) }); // Join var joined = orders .Join(customers, o => o.CustomerId, c => c.Id, (o,c) => new { o.Total, c.Name }); // SelectMany (flatten) var tags = posts .SelectMany(p => p.Tags) .Distinct(); // Distinct / Skip / Take nums.Distinct(); nums.Skip(2).Take(3);
Write non-blocking code with async/await, Task, Task<T>, cancellation tokens and parallel operations.
// async method returning Task<T> public async Task<string> FetchDataAsync( string url) { using var http = new HttpClient(); return await http.GetStringAsync(url); } // void-returning async public async Task SaveAsync(Data d) { await _repo.SaveAsync(d); await _cache.InvalidateAsync(); } // ValueTask (alloc-free) public async ValueTask<int> GetAsync() => await _source.ReadAsync(); // ConfigureAwait (avoid deadlock) await task.ConfigureAwait(false);
// Run multiple tasks in parallel var t1 = FetchAsync("url1"); var t2 = FetchAsync("url2"); var (r1,r2) = await (t1, t2); // WhenAll — wait for all var results = await Task.WhenAll(t1, t2); // WhenAny — first completed var winner = await Task.WhenAny(t1, t2); // Task.Run — background thread var res = await Task.Run(() => HeavyComputation()); // Parallel.ForEachAsync (NET 6+) await Parallel.ForEachAsync( items, async (item, ct) => { await ProcessAsync(item); });
// CancellationToken public async Task DoWorkAsync( CancellationToken ct) { await _service.RunAsync(ct); } var cts = new CancellationTokenSource(); cts.CancelAfter(5000); // 5s timeout await DoWorkAsync(cts.Token); // IAsyncEnumerable (async stream) public async IAsyncEnumerable<int> GenerateAsync() { for (int i=0; i<10; i++) { await Task.Delay(100); yield return i; } } await foreach (var n in GenerateAsync()) Console.WriteLine(n);
Write reusable, type-safe code with generic classes, methods, constraints and built-in delegate types.
// Generic class public class Repository<T> where T : IEntity, new() { private List<T> _store = []; public void Add(T item) => _store.Add(item); public IEnumerable<T> GetAll() => _store; } // Generic method public static T Max<T>(T a, T b) where T : IComparable<T> => a.CompareTo(b) >= 0 ? a : b; // Common constraints // where T : class — reference type // where T : struct — value type // where T : new() — has parameterless ctor // where T : IFoo — implements interface // where T : notnull — non-nullable
// Func<TIn, TOut> Func<int,int,int> add = (a,b) => a+b; add(3,4); // 7 // Action<T> — returns void Action<string> print = msg => Console.WriteLine(msg); // Predicate<T> — returns bool Predicate<int> isEven = n => n%2==0; // Events public event EventHandler<string>? OnSaved; // raise OnSaved?.Invoke(this, "Saved!"); // subscribe svc.OnSaved += (s,e) => Console.WriteLine(e); // Expression trees Expression<Func<int,bool>> expr = x => x > 5;
Build APIs, minimal APIs and web apps with ASP.NET Core. Configure middleware, routing, filters and responses.
var builder = WebApplication.CreateBuilder(args); builder.Services.AddScoped<IProductService, ProductService>(); var app = builder.Build(); app.UseHttpsRedirection(); // GET endpoint app.MapGet("/products", async (IProductService svc) => Results.Ok(await svc.GetAllAsync())); // POST endpoint app.MapPost("/products", async (Product p, IProductService svc) => { await svc.CreateAsync(p); return Results.Created( $"/products/{p.Id}", p); }); app.Run();
[ApiController] [Route("api/[controller]")] public class ProductsController : ControllerBase { private readonly IProductService _svc; public ProductsController( IProductService svc) => _svc=svc; [HttpGet] public async Task<IActionResult> GetAll() => Ok(await _svc.GetAllAsync()); [HttpGet("{id:int}")] public async Task<IActionResult> GetById(int id) { var p = await _svc.GetAsync(id); return p is null ? NotFound():Ok(p); } [HttpPost] public async Task<IActionResult> Create(Product p) { await _svc.CreateAsync(p); return CreatedAtAction( nameof(GetById), new { p.Id }, p); } }
// Custom middleware app.Use(async (ctx, next) => { // before await next(); // after }); // Configuration binding var conn = builder.Configuration .GetConnectionString("Default"); // Strongly-typed options builder.Services .Configure<JwtOptions>( builder.Configuration .GetSection("Jwt")); // Exception handling middleware app.UseExceptionHandler("/error"); // Common pipeline app.UseAuthentication(); app.UseAuthorization(); app.MapControllers();
Register services with the built-in IoC container. Understand lifetime scopes, constructor injection and IServiceProvider.
var services = builder.Services; // Transient — new instance each time services.AddTransient< IEmailService, SmtpEmailService>(); // Scoped — one per HTTP request services.AddScoped< IProductRepo, EfProductRepo>(); // Singleton — one for app lifetime services.AddSingleton< ICacheService, MemoryCacheService>(); // Register with factory services.AddScoped<IDbContext>(sp => new AppDbContext( sp.GetRequiredService<DbOptions>())); // Register by implementation type services.AddScoped<MyService>(); // Keyed services (NET 8+) services.AddKeyedScoped<IParser, JsonParser>("json");
| Lifetime | When Resolved | Best For |
|---|---|---|
| Transient | Every injection | Lightweight, stateless services |
| Scoped | Per request | DB context, unit of work |
| Singleton | App start, once | Config, cache, HTTP client |
// Constructor injection public class OrderService { private readonly IProductRepo _repo; private readonly IEmailService _email; private readonly ILogger<OrderService> _log; public OrderService( IProductRepo repo, IEmailService email, ILogger<OrderService> log) { _repo=repo; _email=email; _log=log; } }
Map C# classes to database tables. Perform CRUD operations, migrations, eager/lazy loading and raw SQL queries.
// Entity public class Product { public int Id { get; set; } public string Name { get; set; } = ""; public decimal Price { get; set; } public int CategoryId{ get; set; } public virtual Category? Category{ get; set; } } // DbContext public class AppDbContext : DbContext { public DbSet<Product> Products { get; set; } public DbSet<Category> Categories { get; set; } protected override void OnModelCreating(ModelBuilder mb) { mb.Entity<Product>() .Property(p=>p.Price) .HasPrecision(18,2); } }
// Create _ctx.Products.Add(new Product{ Name="Pen", Price=1.99m }); await _ctx.SaveChangesAsync(); // Read (LINQ on DbSet) var all = await _ctx.Products .AsNoTracking() .ToListAsync(); var p = await _ctx.Products .Include(x=>x.Category) .FirstOrDefaultAsync(x=>x.Id==1); // Update p!.Price = 2.49m; await _ctx.SaveChangesAsync(); // Delete _ctx.Products.Remove(p!); await _ctx.SaveChangesAsync(); // Bulk delete (NET 7+) await _ctx.Products .Where(p=>p.Price<1m) .ExecuteDeleteAsync();
# Add a migration dotnet ef migrations add InitialCreate # Apply migrations to DB dotnet ef database update # Revert to previous migration dotnet ef database update PreviousMigration # Remove last migration (not applied) dotnet ef migrations remove # Generate SQL script dotnet ef migrations script # List migrations dotnet ef migrations list # Drop database dotnet ef database drop --force
Repository, CQRS, Options, Result and exception handling patterns commonly used in production .NET applications.
// try / catch / finally try { await RiskyOperationAsync(); } catch (HttpRequestException ex) when (ex.StatusCode == 404) { _log.LogWarning("Not found"); } catch (Exception ex) { _log.LogError(ex, "Failed"); throw; } finally { Cleanup(); } // Custom exception public class NotFoundException : Exception { public NotFoundException(string msg) : base(msg) {} } // Result pattern public record Result<T>( T? Value, bool IsSuccess, string? Error ) { public static Result<T> Ok(T v) => new(v, true, null); public static Result<T> Fail(string e) => new(default, false, e); }
// Extension methods public static class StringExtensions { public static bool IsNullOrEmpty( this string? s) => string.IsNullOrEmpty(s); public static string Truncate( this string s, int max) => s.Length <= max ? s : s[..max] + "…"; } // Usage "hello world".Truncate(5); // "hello…" // Pattern matching (advanced) var desc = shape switch { Circle { Radius: > 10 } => "big circle", Circle c => $"circle r={c.Radius}", Rectangle r => $"{r.W}x{r.H}", null => "no shape", _ => "unknown" };
Write unit tests with xUnit, mock dependencies with Moq and build integration tests with WebApplicationFactory.
public class ProductServiceTests { [Fact] public void GetPrice_Returns_Correct() { // Arrange var svc = new ProductService(); // Act var price = svc.GetPrice(1); // Assert Assert.Equal(9.99m, price); } [Theory] [InlineData(1, true)] [InlineData(0, false)] public void IsValid_Works( int id, bool expected) { var svc = new ProductService(); Assert.Equal(expected, svc.IsValid(id)); } [Fact] public async Task Create_Throws_When_Null() => await Assert.ThrowsAsync< ArgumentNullException>( () => _svc.CreateAsync(null!)); }
var mockRepo = new Mock<IProductRepo>(); // Setup return value mockRepo .Setup(r => r.GetAsync(1)) .ReturnsAsync(new Product{ Id=1, Name="Pen" }); // Setup exception mockRepo .Setup(r => r.GetAsync(99)) .ThrowsAsync(new NotFoundException("x")); // Inject mock into service var svc = new ProductService(mockRepo.Object); // Verify call was made mockRepo.Verify( r => r.SaveAsync(It.IsAny<Product>()), Times.Once());
public class ApiTests : IClassFixture<WebApplicationFactory<Program>> { private readonly HttpClient _client; public ApiTests( WebApplicationFactory<Program> factory) => _client = factory .WithWebHostBuilder(b => { b.ConfigureServices(s => s.AddSingleton( new Mock<IProductRepo>().Object)); }) .CreateClient(); [Fact] public async Task GetProducts_Returns_200() { var resp = await _client .GetAsync("/api/products"); resp.EnsureSuccessStatusCode(); } }
Spans, Source Generators, primary constructors (C# 12), required members and global usings.
// File-scoped namespace (C# 10) namespace MyApp.Services; // Global using (C# 10) global using System.Text.Json; // Required members (C# 11) public class Config { public required string ApiKey { get; init; } } var cfg = new Config{ ApiKey="abc" }; // Primary constructors (C# 12) public class OrderService( IOrderRepo repo, ILogger<OrderService> log) { public async Task ProcessAsync(int id) { var o = await repo.GetAsync(id); log.LogInformation("Processing {id}",id); } }
# Create new project dotnet new webapi -n MyApi dotnet new console -n MyApp dotnet new classlib # Build & run dotnet build dotnet run dotnet watch run # hot reload # Package management dotnet add package Newtonsoft.Json dotnet remove package Newtonsoft.Json dotnet list package # Testing dotnet test dotnet test --logger "console;verbosity=normal" # Publish dotnet publish -c Release -o ./publish # Self-contained executable dotnet publish -r linux-x64 \ --self-contained true
Grow your full-stack and DevOps skills with our free developer reference library.