总目录
前言
在C# 7.0及更高版本中,弃元(Discard)是一个新的语言特性,允许开发者在特定情况下忽略某些值。弃元用下划线 _
作为占位符,明确表示忽略某个值,提升代码可读性
一、弃元是什么?
1. 基本概念
弃元(Discard)是 C# 7.0 引入的占位符变量,用下划线 _
表示,用于显式声明某个值无需使用。它不会分配内存空间,甚至能减少编译器警告,让代码意图更明确。
- 弃元是 C# 中的一个语言特性,用于在声明变量或表达式时显式地指定一个“不关心”的占位符。
- 它使用下划线 _ 作为标识符,告诉编译器在这里不需要分配内存或存储数据,仅仅是为了语法的完整性而存在。
- 从 C# 7.0 开始,C# 支持弃元,这是一种在应用程序代码中人为取消使用的占位符变量。 弃元相当于未赋值的变量;它们没有值。 因为只有一个弃元变量,甚至不为该变量分配存储空间,所以弃元可减少内存分配。 因为它们使代码的意图清楚,增强了其可读性和可维护性。
2. 核心特性
- 内存零分配:编译器不为弃元变量分配存储空间(弃元不存储值)
- 意图明确化:明确告知开发者和编译器“此值无需使用”,编译器可能优化相关代码
- 跨场景适配:适用于元组、模式匹配、异步编程等20+种场景
3. 注意事项
不可读取值:弃元
_
一旦声明,后续代码中不能访问其值。var _ = 10; Console.WriteLine(_); // 编译错误:弃元不可读取
作用域限制:同一作用域内
_
只能作为弃元,不能重新定义为普通变量。与
var
的区别:var
是类型推断,_
是显式弃元。
二、弃元的使用
1. 元组和对象的析构
对于Deconstruct 不了解的,可以查看C# Deconstruct详解。
1)元组的析构
如果应用程序代码使用某些元组元素,但忽略其他元素,这时使用弃元来处理元组就会很有用
// 使用弃元忽略元组中的第一个和第二个元素
var(_,_,id) = ("jack","123",3);
static void Main(string[] args)
{
//通过使用 弃元,忽略age的值,只取name的值
(var name, _) = GetUser();
Console.WriteLine($"name:{name}");
Console.ReadKey();
}
//该方法 返回类型为 元组
public static (string name, int age) GetUser()
{
return ("张三", 33);
}
2)对象的析构
类、结构或接口的 Deconstruct 方法还允许从对象中检索和析构一组特定的数据。 如果想只使用析构值的一个子集,可使用弃元。
定义一个Person类,并在该类中定义了多个析构函数
public class Person
{
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
public string City { get; set; }
public string State { get; set; }
//定义构造函数
public Person(string fname, string mname, string lname,
string cityName, string stateName)
{
FirstName = fname;
MiddleName = mname;
LastName = lname;
City = cityName;
State = stateName;
}
// 定义析构函数
public void Deconstruct(out string fname, out string lname)
{
fname = FirstName;
lname = LastName;
}
// 定义析构函数的重载
public void Deconstruct(out string fname, out string mname, out string lname)
{
fname = FirstName;
mname = MiddleName;
lname = LastName;
}
// 定义析构函数的重载
public void Deconstruct(out string fname, out string lname,
out string city, out string state)
{
fname = FirstName;
lname = LastName;
city = City;
state = State;
}
}
析构函数的运用,Person中有很多的属性,但是我只想取得其中部分属性的值:
class Example
{
public static void Main()
{
var p = new Person("John", "Quincy", "Adams", "Boston", "MA");
// 析构Person这个对象,并且只获取fName 和 city两个参数,其余的忽略
var (fName, _, city, _) = p;
Console.WriteLine($"Hello {fName} of {city}!");// Hello John of Boston!
}
}
2. 匹配模式中的弃元
static void Main()
{
object obj = new int[] { 1, 2, 3 };
switch (obj)
{
case int[] _ when ((int[])obj).Length > 2:
Console.WriteLine("数组长度大于2");
break;
case null:
Console.WriteLine("空值");
break;
default:
Console.WriteLine("其他类型");
break;
}
}
internal class MyClass
{
private int v1;
private string v2;
public MyClass(int v1, string v2)
{
this.v1 = v1;
this.v2 = v2;
}
}
static void Main(string arg)
{
object obj = new MyClass(10, "test");
// 使用弃元忽略 MyClass 对象
if (obj is MyClass _)
{
Console.WriteLine("Matched MyClass type");
}
}
3. 异步方法中的弃元
明确表达“关注执行而非结果”
// 异步执行且忽略返回值
static void Main()
{
_ = Task.Run(() => Log("异步任务执行"));
}
public static void Log(string data)
{
Console.WriteLine(data);
}
static void Main(string arg)
{
_= GetResultAsync(); // 使用弃元忽略异步方法的结果
}
async static Task<int> GetResultAsync()
{
await Task.Delay(1000);
return 10;
}
4. out
参数与方法返回值
// 忽略 TryParse 的布尔返回值
int.TryParse("123", out _);
// 忽略方法返回值
_ = GetConfig(); // 假设 GetConfig() 返回重要配置
注意:弃元不能读取值,否则会报错 CS0103
5. 迭代元素时的弃元
迭代元素时的弃元: 用于忽略迭代过程中的某些值。
var dictionary = new Dictionary<string, int>
{
["apple"] = 1,
["banana"] = 2,
["cherry"] = 3
};
// 使用弃元忽略键,只处理值
foreach (var (_, value) in dictionary)
{
Console.WriteLine(value); // 输出:1 2 3
}
6. 独立弃元与空合并运算符
// 独立弃元:强制空值检查
_ = arg ?? throw new ArgumentNullException();
// 结合 null 合并运算符
var result = data ?? _ = LoadData();
场景:
- 防止空引用异常
- 确保副作用(如
LoadData()
)被执行
弃元是 C# 提升代码简洁性的“语法糖”,通过合理使用下划线 _
,能够帮助开发人员编写更为简洁和清晰的代码。通过使用弃元,可以有效地忽略不需要的变量或返回值,提高代码的可读性和维护性。在实际开发中,根据需要合理地运用弃元,可以使代码更加精简和易于理解。
结语
回到目录页:C# 知识汇总
以上就是本文的内容,希望以上内容可以帮助到您,如文中有不对之处,还请批评指正。
参考资料:
弃元 - C#指南
C# 弃元的详解与示例
MSDN弃元
MSDN析构元组