控制器中用Pattern Matching实现请求路由与对象转换返回方案咨询
Great question! Let's break this down step by step using C#'s pattern matching (since you're working with an API controller, I'll assume you're using .NET) to eliminate those messy if statements and make your code cleaner and more maintainable.
First, let's start with a realistic complex Order structure to work with:
public class Order { public int Id { get; set; } public OrderStatus Status { get; set; } public OrderType Type { get; set; } public decimal TotalAmount { get; set; } public Customer Customer { get; set; } public DateTime CreatedDate { get; set; } // Other complex properties... } public enum OrderStatus { Pending, Paid, Shipped, Cancelled } public enum OrderType { Standard, Premium, Bulk } public class Customer { public bool IsVip { get; set; } public string Email { get; set; } }
Step 1: Match the generic input to a concrete Order type
Instead of checking if (input is Order order) separately, we can integrate type matching directly into our pattern matching logic. This handles both type validation and conversion in one step.
Step 2: Use pattern matching to determine return types
We'll use a switch expression (available in C# 8+) to replace all your if/else chains. This lets you combine type checks, property conditions, and even complex logic into concise, readable branches.
Here's how your API controller method would look:
[HttpPost("process-order")] public IActionResult ProcessOrder([FromBody] object input) { return input switch { // Match pending standard orders Order { Status: OrderStatus.Pending, Type: OrderType.Standard } order => Ok(new StandardPendingResponse { OrderId = order.Id, NextAction = "Complete your payment via our portal" }), // Match high-value paid orders (total > $1000) Order { Status: OrderStatus.Paid, TotalAmount: > 1000 } order => Ok(new HighValuePaidResponse { OrderId = order.Id, DiscountApplied = 0.1m, ConfirmationEmailSent = true }), // Match VIP customers with shipped orders Order { Status: OrderStatus.Shipped, Customer: { IsVip: true } } order => Ok(new VipShippedResponse { OrderId = order.Id, TrackingUrl = $"https://track.example.com/{order.Id}", PrioritySupportLine = "1-800-VIP-ORDER" }), // Handle complex conditional logic with `when` clauses Order order when order.TotalAmount > 5000 && order.CreatedDate.AddDays(3) < DateTime.Now => Ok(new OverdueLargeOrderResponse { OrderId = order.Id, ReminderSent = true, LateFee = order.TotalAmount * 0.05m }), // Catch all other Order cases Order _ => BadRequest("Unsupported order configuration"), // Catch non-Order input types _ => BadRequest("Invalid input type: expected an Order object") }; }
Key Benefits of This Approach
- Cleaner, more readable code: All logic lives in one place instead of scattered across if/else blocks.
- Built-in type safety: The compiler ensures you're working with a valid
Orderinstance in each branch (no null checks needed here, since the pattern only matches non-null Order objects). - Easy to extend: Adding a new order type or status just requires adding a new switch branch—no need to hunt through nested ifs.
- Comprehensive coverage: The final
Order _and_branches ensure you handle every possible input case, eliminating unexpected nulls or unhandled scenarios.
Quick Notes
- Make sure your API is correctly deserializing the request body into an
Order(using[FromBody]helps with this in ASP.NET Core). - If you need to handle multiple input types (not just
Order), you can add additional type patterns to the switch (e.g.,Invoice invoice => Ok(new InvoiceResponse(...))). - For even more complex scenarios, you can create custom pattern matching methods or use positional patterns if your
Orderhas a deconstructor.
内容的提问来源于stack exchange,提问作者Alex Gordon

