C# 14 新特性详解
C# 14 新特性详解
1. 概述
C# 14 是与 .NET 10 一同发布的最新主要版本,引入了多项新功能来提升开发效率和代码表达能力。这些新特性包括扩展成员、field 关键字、隐式跨度转换、未绑定泛型类型支持等。
2. 扩展成员 (Extension Members)
2.1 扩展属性和索引器
C# 14 引入了新的扩展成员语法,不仅支持扩展方法,还支持扩展属性和索引器:
public static class EnumerableExtensions
{// 扩展块 - 为实例成员扩展extension<TSource>(IEnumerable<TSource> source){// 扩展属性public bool IsEmpty => !source.Any();// 扩展索引器public TSource this[int index] => source.Skip(index).First();// 扩展方法public IEnumerable<TSource> Where(Func<TSource, bool> predicate) {// 实现...}}// 扩展块 - 为静态成员扩展extension<TSource>(IEnumerable<TSource>){// 静态扩展方法public static IEnumerable<TSource> Combine(IEnumerable<TSource> first, IEnumerable<TSource> second) {// 实现...}// 静态扩展属性public static IEnumerable<TSource> Identity => Enumerable.Empty<TSource>();}
}
2.2 使用示例
var sequence = new List<int> { 1, 2, 3 };// 调用扩展属性(实例成员)
bool isEmpty = sequence.IsEmpty;// 调用扩展索引器
int item = sequence[1];// 调用静态扩展属性
var identity = IEnumerable<int>.Identity;// 调用静态扩展方法
var combined = IEnumerable<int>.Combine(sequence, new[] { 4, 5 });
3. field 关键字
3.1 简化属性实现
field
关键字允许编写属性访问器而无需显式声明后备字段:
// 传统方式
private string _message;
public string Message
{get => _message;set => _message = value ?? throw new ArgumentNullException(nameof(value));
}// C# 14 方式
public string Message
{get;set => field = value ?? throw new ArgumentNullException(nameof(value));
}
3.2 使用场景
// 只读属性
public string Name { get => field; private set => field = value; }// 带验证的属性
public int Age
{get => field;set => field = value >= 0 ? value : throw new ArgumentException("Age cannot be negative");
}// 带日志的属性
public string Status
{get => field;set { Console.WriteLine($"Status changing from {field} to {value}");field = value;}
}
4. 隐式跨度转换
4.1 跨度类型转换增强
C# 14 为 Span<T>
和 ReadOnlySpan<T>
提供了更好的隐式转换支持:
// 数组到 Span 的隐式转换
Span<int> span = new int[] { 1, 2, 3, 4, 5 };// 数组到 ReadOnlySpan 的隐式转换
ReadOnlySpan<int> readOnlySpan = new int[] { 1, 2, 3, 4, 5 };// Span 到 ReadOnlySpan 的隐式转换
ReadOnlySpan<int> readOnlyFromSpan = span;// 字符串到 ReadOnlySpan<char> 的隐式转换
ReadOnlySpan<char> charSpan = "Hello World";
4.2 实际应用
public static void ProcessData(ReadOnlySpan<int> data)
{// 处理数据...foreach (var item in data){Console.WriteLine(item);}
}// 可以直接传入不同类型的参数
ProcessData(new int[] { 1, 2, 3 }); // 数组
ProcessData(stackalloc int[] { 1, 2, 3 }); // 栈分配数组
5. 未绑定泛型类型和 nameof
5.1 nameof 支持未绑定泛型
// C# 14 新特性
string name1 = nameof(List<>); // 返回 "List"
string name2 = nameof(Dictionary<,>); // 返回 "Dictionary"// 早期版本需要关闭的泛型类型
string name3 = nameof(List<int>); // 返回 "List"
5.2 实际应用场景
public static void LogGenericType<T>()
{Console.WriteLine($"Processing type: {nameof(T)}");
}// 使用示例
LogGenericType<List<string>>(); // 输出: Processing type: List
6. 带修饰符的简单 Lambda 参数
6.1 Lambda 参数修饰符支持
现在可以在不指定参数类型的情况下为 lambda 参数添加修饰符:
delegate bool TryParse<T>(string text, out T result);// C# 14 方式 - 简化的参数声明
TryParse<int> parse1 = (text, out result) => int.TryParse(text, out result);// 传统方式 - 需要完整类型声明
TryParse<int> parse2 = (string text, out int result) => int.TryParse(text, out result);
6.2 支持的修饰符
// ref 修饰符
delegate void ModifyValue(ref int value);
ModifyValue modifier = (ref int x) => x *= 2;// in 修饰符(只读引用)
delegate void ReadValue(in int value);
ReadValue reader = (in int x) => Console.WriteLine(x);// scoped 修饰符
delegate void ScopedOperation(scoped ReadOnlySpan<int> span);
ScopedOperation operation = (scoped ReadOnlySpan<int> data) =>
{// 处理数据...
};
7. Partial 构造函数和事件
7.1 Partial 构造函数
public partial class Person
{// 构造函数定义声明public partial Person(string name, int age);// 构造函数实现声明public partial Person(string name, int age){Name = name;Age = age;}
}public partial class Person
{public string Name { get; }public int Age { get; }
}
7.2 Partial 事件
public partial class EventPublisher
{// 事件定义声明public partial event EventHandler<string> MessageReceived;// 事件实现声明public partial event EventHandler<string> MessageReceived{add { /* 添加事件处理程序 */ }remove { /* 移除事件处理程序 */ }}
}
8. 用户自定义复合赋值运算符
8.1 自定义复合赋值
public class Counter
{public int Value { get; set; }// 用户定义的复合赋值运算符public static Counter operator +=(Counter left, int right){left.Value += right;return left;}public static Counter operator -=(Counter left, int right){left.Value -= right;return left;}
}// 使用示例
var counter = new Counter { Value = 10 };
counter += 5; // Value 现在是 15
counter -= 3; // Value 现在是 12
9. Null 条件赋值
9.1 简化 Null 检查
// C# 14 之前的方式
if (customer != null)
{customer.Order = GetCurrentOrder();
}// C# 14 方式 - Null 条件赋值
customer?.Order = GetCurrentOrder();
9.2 复合赋值支持
// 支持复合赋值运算符
customer?.Balance += 100;
customer?.Items?.Add(newItem);// 不支持递增和递减运算符
// customer?.Count++; // 编译错误
// customer?.Count--; // 编译错误
9.3 短路求值
public class ExpensiveOperation
{public static string GetExpensiveResult() {Console.WriteLine("执行昂贵操作");return "Result";}
}// 只有在 customer 不为 null 时才会执行 GetExpensiveResult()
customer?.Description = ExpensiveOperation.GetExpensiveResult();
10. 最佳实践和注意事项
10.1 扩展成员使用建议
// 好的做法:为相关功能分组
extension<T>(IEnumerable<T> source)
{public bool IsNullOrEmpty => source == null || !source.Any();public T SecondOrDefault() => source.Skip(1).FirstOrDefault();
}// 避免:过度使用扩展成员导致 API 混乱
10.2 field 关键字注意事项
public class Example
{// 当存在同名符号时,需要消除歧义private string field = "instance field";public string Property{get => @field; // 或 this.fieldset => @field = value;}
}
10.3 性能考虑
// 利用 Span 的隐式转换提高性能
public static void ProcessString(ReadOnlySpan<char> text)
{// 避免不必要的字符串分配for (int i = 0; i < text.Length; i++){// 处理字符...}
}// 可以直接传入字符串
ProcessString("Hello World"); // 隐式转换为 ReadOnlySpan<char>
11. 总结
C# 14 引入了以下主要新特性:
- 扩展成员:支持扩展属性、索引器和静态扩展成员
- field 关键字:简化属性实现,无需显式声明后备字段
- 隐式跨度转换:增强 Span 和 ReadOnlySpan 的使用体验
- 未绑定泛型支持:nameof 操作符支持未绑定泛型类型
- Lambda 参数修饰符:简化 lambda 参数声明
- Partial 构造函数和事件:支持分部构造函数和事件声明
- 用户自定义复合赋值:允许自定义复合赋值运算符
- Null 条件赋值:简化 Null 检查和赋值操作
这些新特性使 C# 代码更加简洁、表达力更强,同时保持了类型安全和性能优势。开发者应该根据具体场景合理使用这些新功能,以提高代码质量和开发效率。