Claude
Skills
Sign in
Back

csharp-dotnet

Included with Lifetime
$97 forever

C# and .NET development patterns

Generalcsharpdotnetasynclinqaspnet

What this skill does


# C# & .NET

## Overview

Modern C# and .NET development patterns including async programming, LINQ, and ASP.NET Core.

---

## Modern C# Features

### Records and Init-Only Properties

```csharp
// Record type (immutable by default)
public record User(
    string Id,
    string Email,
    string Name,
    DateTime CreatedAt
);

// With-expressions for immutable updates
var user = new User("1", "[email protected]", "Test User", DateTime.UtcNow);
var updated = user with { Name = "Updated Name" };

// Record with validation
public record ValidatedUser
{
    public required string Id { get; init; }
    public required string Email { get; init; }
    public required string Name { get; init; }

    public ValidatedUser()
    {
        // Validation in constructor
    }

    // Custom validation
    public static ValidatedUser Create(string email, string name)
    {
        if (!email.Contains("@"))
            throw new ArgumentException("Invalid email");

        return new ValidatedUser
        {
            Id = Guid.NewGuid().ToString(),
            Email = email,
            Name = name
        };
    }
}

// Init-only properties
public class Config
{
    public required string ConnectionString { get; init; }
    public int Timeout { get; init; } = 30;
}
```

### Pattern Matching

```csharp
// Type patterns
public string Describe(object obj) => obj switch
{
    string s => $"String of length {s.Length}",
    int i when i > 0 => $"Positive integer: {i}",
    int i => $"Non-positive integer: {i}",
    IEnumerable<int> list => $"Integer list with {list.Count()} items",
    null => "Null value",
    _ => "Unknown type"
};

// Property patterns
public decimal CalculateDiscount(Order order) => order switch
{
    { Total: > 1000, Customer.IsPremium: true } => order.Total * 0.2m,
    { Total: > 1000 } => order.Total * 0.1m,
    { Customer.IsPremium: true } => order.Total * 0.05m,
    _ => 0
};

// List patterns (C# 11)
public string DescribeList(int[] numbers) => numbers switch
{
    [] => "Empty",
    [var single] => $"Single element: {single}",
    [var first, var second] => $"Two elements: {first}, {second}",
    [var first, .. var middle, var last] => $"First: {first}, Last: {last}, Middle count: {middle.Length}",
};

// Positional patterns with deconstruct
public record Point(int X, int Y);

public string Quadrant(Point point) => point switch
{
    (0, 0) => "Origin",
    (> 0, > 0) => "First quadrant",
    (< 0, > 0) => "Second quadrant",
    (< 0, < 0) => "Third quadrant",
    (> 0, < 0) => "Fourth quadrant",
    (_, 0) or (0, _) => "On an axis"
};
```

### Nullable Reference Types

```csharp
#nullable enable

public class UserService
{
    // Non-nullable (compiler ensures not null)
    public User GetUser(string id)
    {
        return _repository.Find(id)
            ?? throw new NotFoundException($"User {id} not found");
    }

    // Nullable return
    public User? FindUser(string id)
    {
        return _repository.Find(id);
    }

    // Null handling
    public string GetDisplayName(User? user)
    {
        // Null-conditional
        var name = user?.Name;

        // Null-coalescing
        return user?.Name ?? "Anonymous";

        // Null-coalescing assignment
        // user ??= CreateDefaultUser();
    }

    // Null-forgiving operator (use sparingly)
    public void ProcessUser(User? user)
    {
        // When you know it's not null but compiler doesn't
        var name = user!.Name;
    }
}

// Required members (C# 11)
public class RequiredUser
{
    public required string Id { get; init; }
    public required string Email { get; init; }
    public string? Nickname { get; init; }
}
```

---

## Async Programming

```csharp
using System.Threading.Tasks;
using System.Threading;

public class AsyncService
{
    // Basic async method
    public async Task<User> GetUserAsync(string id, CancellationToken ct = default)
    {
        var response = await _httpClient.GetAsync($"/users/{id}", ct);
        response.EnsureSuccessStatusCode();
        return await response.Content.ReadFromJsonAsync<User>(ct)
            ?? throw new InvalidOperationException("Null response");
    }

    // Parallel execution
    public async Task<IReadOnlyList<User>> GetUsersAsync(IEnumerable<string> ids)
    {
        var tasks = ids.Select(id => GetUserAsync(id));
        return await Task.WhenAll(tasks);
    }

    // With error handling
    public async Task<Result<User>> SafeGetUserAsync(string id)
    {
        try
        {
            var user = await GetUserAsync(id);
            return Result<User>.Success(user);
        }
        catch (Exception ex)
        {
            return Result<User>.Failure(ex.Message);
        }
    }

    // ValueTask for potentially synchronous operations
    public ValueTask<User?> GetCachedUserAsync(string id)
    {
        if (_cache.TryGetValue(id, out var user))
        {
            return ValueTask.FromResult<User?>(user);
        }

        return new ValueTask<User?>(FetchAndCacheUserAsync(id));
    }

    // Async enumerable (IAsyncEnumerable)
    public async IAsyncEnumerable<User> StreamUsersAsync(
        [EnumeratorCancellation] CancellationToken ct = default)
    {
        var page = 1;
        while (true)
        {
            var users = await FetchPageAsync(page, ct);
            if (!users.Any()) yield break;

            foreach (var user in users)
            {
                yield return user;
            }
            page++;
        }
    }

    // Consuming async enumerable
    public async Task ProcessAllUsersAsync()
    {
        await foreach (var user in StreamUsersAsync())
        {
            await ProcessUserAsync(user);
        }
    }
}

// Channels for producer-consumer
public class ChannelExample
{
    private readonly Channel<Message> _channel = Channel.CreateBounded<Message>(100);

    public async Task ProduceAsync(Message message)
    {
        await _channel.Writer.WriteAsync(message);
    }

    public async Task ConsumeAsync(CancellationToken ct)
    {
        await foreach (var message in _channel.Reader.ReadAllAsync(ct))
        {
            await ProcessMessageAsync(message);
        }
    }
}
```

---

## LINQ

```csharp
using System.Linq;

public class LinqExamples
{
    // Query syntax
    public IEnumerable<User> GetActiveUsers(IEnumerable<User> users)
    {
        return from user in users
               where user.IsActive
               orderby user.Name
               select user;
    }

    // Method syntax (more common)
    public IEnumerable<string> GetActiveUserEmails(IEnumerable<User> users)
    {
        return users
            .Where(u => u.IsActive)
            .OrderBy(u => u.Name)
            .Select(u => u.Email);
    }

    // Grouping
    public IDictionary<string, List<User>> GroupByDomain(IEnumerable<User> users)
    {
        return users
            .GroupBy(u => u.Email.Split('@')[1])
            .ToDictionary(g => g.Key, g => g.ToList());
    }

    // Join
    public IEnumerable<OrderWithUser> JoinOrdersWithUsers(
        IEnumerable<Order> orders,
        IEnumerable<User> users)
    {
        return orders.Join(
            users,
            order => order.UserId,
            user => user.Id,
            (order, user) => new OrderWithUser(order, user));
    }

    // Aggregate
    public OrderStats GetOrderStats(IEnumerable<Order> orders)
    {
        return new OrderStats(
            Count: orders.Count(),
            Total: orders.Sum(o => o.Amount),
            Average: orders.Average(o => o.Amount),
            Max: orders.Max(o => o.Amount)
        );
    }

    // SelectMany (flatten)
    public IEnumerable<OrderItem> GetAllItems(IEnumerable<Order> orders)
    {
        return orders.SelectMany(o => o.Items);
    }

    // Complex pipeline
    public IEnumerable<UserSummary> GetTopCustomers(
        IEnumerable<User> users,
        IEnumerable<Order> orders)
    {
        return orders
            .GroupBy(o => o.UserId)
        

Related in General