模式匹配是一种在多种编程语言中广泛使用的功能性编程特性,如Scala、Rust、Python、Haskell、Prolog等。C#从7.0版本开始引入了模式匹配,并且随着后续主要版本的发布,它持续获得了许多更新。本文将帮助了解C#中模式匹配的各种类型,并为每种类型提供使用示例。
记住,只能在'is'表达式或'switch'表达式中应用模式匹配。
模式匹配提供了以下好处:
对表达式进行类型测试:
public bool IsProductFood(object product) {
return product is FoodModel;
}
在表达式匹配成功后,进行类型测试并赋值给变量:
public bool IsProductFoodThatRequiresRefrigeration(object product) {
return product is FoodModel food && RequiresRefrigeration(food.StorageTemperature);
}
测试与常量值的匹配,可以包括int、float、char、string、bool、enum、用const声明的字段、null:
public bool IsFreshProduce(FoodModel food) {
return food?.Category?.ID is (int) ProductCategoryEnum.FreshProduce;
}
检查引用或可空类型是否为null:
public bool FoodDoesNotExist(FoodModel food) {
return food is null;
}
类似于类型模式,var模式匹配表达式并检查null,同时将值赋给变量。var类型根据匹配表达式的编译时类型声明:
public bool IsProductFoodThatRequiresRefrigeration(FoodModel food) {
return GetFoodStorageRequirements(food) is var storageRequirement && storageRequirement is StorageRequirementEnum.Freezer;
}
这是一种非常有用的模式匹配类型,可以使用对象成员而不是变量来匹配给定条件。它可以轻松地与其他模式匹配类型一起使用,如相对模式、模式组合器等,以构建灵活且强大的逻辑表达式:
public bool IsOrganicFood(FoodModel food) {
return food is {
NonGMO: true,
NoChemicalFertilizers: true,
NoSyntheticPesticides: true
};
}
使用废弃操作符_进行模式匹配,可以匹配任何东西,包括null。在新的switch表达式中,它的使用非常出色,用于匹配默认或else情况。以下示例中,如果food的存储温度未提供或数字不匹配以下范围,则抛出自定义异常:
public int GetFoodStorageTemperature(StorageRequirementEnum storageRequirement) => storageRequirement switch {
StorageRequirementEnum.Freezer => -18,
StorageRequirementEnum.Refrigerator => 4,
StorageRequirementEnum.RoomTemperature => 25,
_ => throw new InvalidStorageRequirementException()
};
主要用于struct类型,利用类型的析构函数根据析构函数中值的位置匹配模式:
public bool IsFreeFood(FoodModel food) {
return food.Price is (0, _);
}
这是位置模式的一个特殊派生,可以在同一个表达式中测试类型的多个属性:
public string GetFoodDescription(FoodModel food) => (food.NonGMO, food.Category.ID) switch {
(true, (int)ProductCategoryEnum.FreshProduce) => "Non-GMO Fresh Product",
(true, (int)ProductCategoryEnum.Dairy) => "Non-GMO Dairy",
(false, (int)ProductCategoryEnum.Meats) => "GMO Meats. Avoid!",
(_, _) => "Invalid Food Group"
};
可以在switch表达式中进行类型检查,而无需使用废弃:
public string CheckValueType(object value) =>
value switch {
int => "This is an integer number",
decimal => "This is a decimal number",
double => "This is a double number",
_ => throw new InvalidNumberException(value)
};
C# 9引入的关系模式允许应用关系运算符>、<、>=、<=来匹配模式与常量或enum值:
public StorageRequirementEnum GetFoodStorageRequirements(FoodModel food) => food.StorageTemperature switch {
<= -18 => StorageRequirementEnum.Freezer,
>= 2 and < 6 => StorageRequirementEnum.Refrigerator,
> 6 and < 30 => StorageRequirementEnum.RoomTemperature,
_ => throw new InvalidStorageRequirementException(food.StorageTemperature)
};
这代表了否定、合取、析取;not、and、or。这些被称为模式组合器。这些用于组合模式并在它们上应用逻辑条件:
public bool RequiresRefrigeration(ProductCategoryEnum productType) {
return productType is ProductCategoryEnum.Dairy or ProductCategoryEnum.Meats;
}
检查表达式是否为非null值:
public bool BlogExists(BlogModel blog) {
return blog is not null;
}
这允许使用括号来控制执行顺序,并将逻辑表达式组合在一起。它可以与任何类型的模式一起使用,但其使用主要与模式组合器的使用相关:
public bool RequiresRefrigeration(int storageTemperature) {
return storageTemperature is > 1 and (< 6);
}
在C# 10中,解决了嵌套属性匹配的语法问题。随着扩展属性模式的引入,现在可以在模式匹配中使用嵌套属性的语法变得清晰简洁:
public bool RequiresRefrigeration(FoodModel food) {
return food is {
Category.ID: (int)ProductCategoryEnum.Dairy or (int)ProductCategoryEnum.Meats
};
}
列表匹配模式是C#中模式匹配的最新补充,可以使用列表模式匹配列表或数组中的一组顺序元素。可以将其与废弃、模式组合器、范围、var、类型赋值模式混合使用,构建非常灵活和强大的列表模式匹配:
public (int?, int?) FindNumberOneAndNumberFour() {
int[] numbers = {1, 2, 3, 4, 5};
// 如果第二个值是任何东西,第三个大于或等于3,第五个是5
if (numbers is [var numberOne, _, >= 3, int numberFour, 5]) {
return (numberOne, numberFour);
}
return (null, null);
}
近年来,C#增加了许多语言特性,帮助开发者在多种平台上构建稳定可靠的应用程序。随着模式匹配特性的增加,C#增加了一种已经在多种编程语言中使用了几十年的强大的功能性编程能力。当然,总是需要谨慎不要过度使用模式匹配。
如果正在与其他团队成员一起工作的大型项目中,记住不是每个人都会了解一些或全部的模式匹配特性,所以不想突然引入太多这些。本文快速而完整地概述了C#中添加的所有模式匹配类型。
如果发现它有用,或者有任何评论,请告诉。
要了解更多关于C#中的模式匹配,可以查看这些参考资料: