我在这里总结了几种我用过的语法糖,和大家分享下。
语法糖一览:
????=?.?[]isasswitch表达式[]^..recordwithrequiredinit
下面我们举个栗子看看:
空值:??、??=、?.
?? 只取值:左边是 null 就用右边,原来的变量不动。
var display = nickName ?? "未命名";
var conn = configuration["Redis"] ?? "localhost:6379";
var title = order.Remark ?? order.Title ?? "无标题";
??= 往回补:左边是 null 才赋值。懒加载最合适。
_counters ??= new Dictionary<string, int>();
对照:var name = input ?? "未命名" 里 input 还是 null;input ??= "未命名" 是把 input 自己补上。
?? 只认 null,不认空字符串。"" ?? "未命名" 还是 ""。
?. / ?[]:中间可能断,安全往下点。整条链任一环是 null,结果就是 null。
var city = user?.Address?.City ?? "未知城市";
var first = items?[0];
order?.Refresh();
注意: 逻辑上订单一定有客户,就写 order.Customer.Name,不要?.吞掉异常。
类型判断:is、as
以前先 as 再判空,绕。is 一边判断一边取出变量;as 只在「转不成就当 null 接着传」时用。
if (obj is User user)
Console.WriteLine(user.Name);
var maybe = payload as User;
SaveOptional(maybe); // 方法接受 User?
不确定类型别强转 (User)obj,不是就抛。新代码优先 is。
switch 模式匹配
老 switch 只能 case 1、case "A" 这种常量。现在可以按类型、按属性、按范围匹配,一串 if is 就能收成一个表达式。
按类型:进来的是什么,就当什么用。
string text = payload switch
{
User u => u.Name,
Order o => o.OrderNo,
string s => s,
null => "空",
_ => "未知"
};
按属性:类型对了还不够,字段也得对上。
string label = order switch
{
{ Status: OrderStatus.Paid, Amount: > 0 } => "可发货",
{ Status: OrderStatus.Pending } => "待支付",
{ Status: OrderStatus.Cancelled } => "已取消",
_ => "其它"
};
按范围:运费、会员等级这种分段,别写 if else。
var freight = weight switch
{
< 1 => 8,
< 5 => 12,
< 20 => 20,
_ => 50
};
再加条件:模式对上之后,还要用 when 滤一层。
var discount = order switch
{
{ Amount: >= 500 } when order.IsVip => 0.8m,
{ Amount: >= 500 } => 0.9m,
{ Amount: >= 200 } => 0.95m,
_ => 1m
};
_ 必须写,否则编译报错。匹配是从上往下,第一条命中就停,所以更具体的写前面。
集合:[]、^、..
int[] arr = [1, 2, 3];
List<string> names = ["张三", "李四"];
int[] merged = [..arr, 4, 5];
var last = arr[^1]; // 最后一个
var tail = arr[^3..]; // 最后三个
var mid = arr[1..^1]; // 去掉头尾
var page = list[skip..(skip + take)];
手机号后四位:phone[^4..]。左边把类型写清,var x = [1, 2] 有时推不出来。
对象:=>、record、with、required
身体只有一句,用表达式体:
public string FullName => $"{First} {Last}";
public UserDto ToDto() => new() { Id = Id, Name = Name };
超过两句就写大括号。
DTO、消息、值对象要「按值比较、改一个字段出新副本」,用 record + with:
public sealed record OrderDto(long Id, string No, decimal Amount);
var b = a with { Amount = 88 }; // a 不变
EF 里要跟踪改属性的实体,用 class,别 with 出一份新的。
创建时必填用 required,初始化后不许改用 init:
public class CreateOrderRequest
{
public required string ProductId { get; init; }
public required int Qty { get; init; }
public string? Remark { get; init; }
}
创建时漏ProductId 编译就报错,可选就不要标required。