My Two Weeks with Claude Sonnet 4.6 for C# Development
Last month, I spent two weeks trying to integrate Claude Sonnet 4.6 into my daily C# workflow, specifically targeting a gnarly .NET 6 Web API codebase that's slowly being migrated to .NET 9. I wasn't looking for a magic bullet, just some pragmatic help.
Our team's been dabbling with AI tools for a while, mostly Copilot and some GPT-4o for documentation. My personal goal was to see if Claude Sonnet 4.6 could genuinely assist with refactoring and debugging existing C# 10 code, or if it was just another glorified autocomplete. I was looking for a fresh perspective, especially on some tricky LINQ queries and async deadlocks that had been haunting us in Visual Studio 2026.
What surprised me about its C# understanding
Honestly, I expected Sonnet 4.6 to struggle with the nuances of C# 10 and our specific domain, but it often surprised me with its contextual understanding. My initial attempts involved pasting small, isolated functions, which worked okay. The real game-changer came when I started feeding it entire .cs files, or even pairs of related files (like a service and its interface). It felt like the Model Context Protocol (MCP) was really helping it build a richer internal model.
For example, I had a complex LINQ query in a repository method that was a performance bottleneck. I pasted the entire ProductRepository.cs file into Claude with a simple prompt. It didn't just suggest a basic Where clause; it understood the intent and proposed an AsQueryable() followed by multiple Where and Select statements, even suggesting an Include for a related entity that wasn't immediately obvious from the method signature alone. It still took me a few tries to get the exact Select projection right.
// Prompt to Claude Sonnet 4.6
/*
Given the following C# 10 code from `ProductRepository.cs`, refactor the `GetFilteredProductsAsync` method to be more performant and readable, especially for filtering by multiple optional criteria.
Consider using `IQueryable` for building the query dynamically.
csharp
// ProductRepository.cs
public class ProductRepository : IProductRepository
{
private readonly AppDbContext _context;
public ProductRepository(AppDbContext context) => _context = context;
public async Task<IEnumerable<Product>> GetFilteredProductsAsync(
string? nameFilter, int? categoryId, decimal? minPrice)
{
var products = await _context.Products
.Where(p =>
(string.IsNullOrEmpty(nameFilter) || p.Name.Contains(nameFilter)) &&
(!categoryId.HasValue || p.CategoryId == categoryId.Value) &&
(!minPrice.HasValue || p.Price >= minPrice.Value))
.ToListAsync();
return products;
}
}
*/
// Claude Sonnet 4.6 Response (excerpt):
/*
Okay, here's a refactored version of `GetFilteredProductsAsync` using `IQueryable` to build the query dynamically, which can be more efficient as the filtering happens at the database level before materialization.
csharp
public async Task> GetFilteredProductsAsync(
string? nameFilter, int? categoryId, decimal? minPrice)
{
IQueryable query = _context.Products;
if (!string.IsNullOrEmpty(nameFilter))
{
query = query.Where(p => p.Name.Contains(nameFilter));
}
if (categoryId.HasValue)
{
query = query.Where(p => p.CategoryId == categoryId.Value);
}
if (minPrice.HasValue)
{
query = query.Where(p => p.Price >= minPrice.Value);
}
// Example of including related data, if needed, for better context awareness
// query = query.Include(p => p.Category);
return await query.ToListAsync();
}
*/
plaintext
This dynamic query building was a definite improvement. The contextual understanding of the existing code was surprisingly robust.
Where it broke and how I learned to prompt better
While its understanding was good, Claude Sonnet 4.6 isn't a mind reader. I screwed up several times by not providing enough explicit detail. For instance, I was debugging a System.Text.Json serialization issue, and Claude initially suggested Newtonsoft.Json attributes or configuration. It took me an embarrassing amount of time to realize I needed to explicitly state our project used System.Text.Json exclusively.
This taught me a critical lesson: even with advanced models like Claude Sonnet 4.6, you still need to be precise. For C# 13 and .NET 9 work, I started adding specific directives to my prompts, like "Using C# 13 and .NET 9, please refactor this..." or "Given this Foo.cs and BarService.cs from our ASP.NET Core 9 project...". This significantly improved the relevance and accuracy of its suggestions.
// My improved prompting style:
"Given the following C# 13 code from `OrderProcessor.cs` and `OrderRepository.cs` in our .NET 9 project, refactor `ProcessOrderAsync` to use a more robust error handling strategy with `IResult` from ASP.NET Core 9, instead of throwing exceptions directly. Assume `OrderRepository.GetByIdAsync` can return null. Also, ensure all database operations are wrapped in a transaction using `_context.Database.BeginTransactionAsync()`."
This level of detail made a huge difference. Without it, I found myself getting generic C# 8 or .NET 6 suggestions that required more manual tweaking than the initial problem warranted. Specificity is key, even for advanced models.
The setup I settled on (for now)
For this personal review, I mostly stuck with the official Claude web interface for Sonnet 4.6, pasting code directly into the chat. I did experiment briefly with a custom VS Code extension that leverages the Claude Opus 4.7 API for larger, multi-file refactors, but for the focused task of evaluating Sonnet 4.6, the web UI was sufficient. My reasoning was simple: minimize integration complexity to isolate the model's performance.
I found myself using Sonnet 4.6 for quick code reviews, suggesting minor refactors, or generating boilerplate for new interfaces based on existing classes. For anything involving significant architectural changes or complex interactions across many files, I still leaned on my own architectural understanding and, if available, the more powerful Claude Opus 4.7. It's not a replacement for Rider 2026 or Visual Studio 2026's deep refactoring tools, but it's a solid complement.
My workflow often looked like this: identify a problematic C# file, paste it into Sonnet 4.6 with a clear prompt, review the suggestions, and then manually apply and refine them in my IDE. I might be wrong about this, but I think this "human-in-the-loop" approach is currently the most effective way to leverage models like Claude Sonnet 4.6 for C# development.
So, after two weeks, Claude Sonnet 4.6 earned a spot in my toolkit, mostly for its ability to quickly parse context and suggest alternative approaches. I'm still figuring out the best way to leverage it for complex, multi-file refactors without turning into a prompt engineer, but it's a solid contender for C# code help. Your mileage may vary, of course.
If you've spent time with Claude Sonnet 4.6 or another model on a particularly tricky C# 13 codebase, I'd genuinely love to hear about your wins and frustrations in the comments.
Top comments (0)