C# 11 中的 List pattern
C# 11 中的 List pattern
Intro
C# 11 将进一步支持增强模式匹配的使用,将会支持对于集合的模式匹配,我们可以结合 C# 8 引入的 Index && Range 来方便的进行集合的模式匹配
Sample
我们直接来看示例吧:
第一组示例如下:
var array =
//new List()
new[]
{
1,2,3,4,5
}
;
if (array is [1, ..])
{
Console.WriteLine("The first one is 1");
}
if (array is [.., 5])
{
Console.WriteLine("The last one is 5");
}
看上面的代码大家应该可以看出来代码是什么意思的了,第一个匹配是集合第一个元素应该是 1,第二个匹配则是集合最后一个元素应该是 5,它等效于下面的代码:
bool flag = array != null && array.Length >= 1 && array[0] == 1;
if (flag)
{
Console.WriteLine("The first one is 1");
}
bool flag2 = array != null && array.Length >= 1 && array[array.Length-1] == 1;
if (flag2)
{
Console.WriteLine("The last one is 5");
}
这个示例有点简单,我们还可以从中间匹配和按范围做匹配,可以参考下面的示例:
if (array is [_, _, 3, ..])
{
Console.WriteLine("The third one is 3");
}
if (array is [.., 4, _])
{
Console.WriteLine("The second to last one is 4");
}
我们可以用 Range 操作符 ..
来表示有若干个元素,对于任意元素的匹配可以使用 _
来匹配,上面代码等价于
bool flag3 = array != null && array.Length >= 3 && array[2] == 3;
if (flag3)
{
Console.WriteLine("The third one is 3");
}
bool flag4 = array != null && array.Length >= 2 && array[array.Length-2] == 4;
if (flag4)
{
Console.WriteLine("The second to last one is 4");
}
匹配序列示例:
if (array is [1, 2, 3, ..])
{
Console.WriteLine("The sequence starts with 1,2,3");
}
if (array is [.., 3, 4, 5])
{
Console.WriteLine("The sequence ends with 3,4,5");
}
if (array is [.., 3, 4, _])
{
Console.WriteLine("The sequence ends with 3,4,_");
}
等价于:
bool flag5 = array != null && array.Length >= 3 && array[0] == 1 && array[1] == 2 && array[2] == 3;
if (flag5)
{
Console.WriteLine("The sequence starts with 1,2,3");
}
bool flag6 = array != null && array.Length>=3 && array[num - 3] == 3 && array[num - 2] == 4 && array[num - 1] == 5;
if (flag6)
{
Console.WriteLine("The sequence ends with 3,4,5");
}
bool flag7 = array != null && array.Length>=3 && array[num - 3] == 3 && array[num - 2] == 4;
if (flag7)
{
Console.WriteLine("The sequence ends with 3,4,_");
}
除了直接元素值的匹配,我们还可以对元素进行类型匹配,可以参考下面这个示例:
var objects = new object[]
{
1, "2", 3.0, "4", Guid.NewGuid()
};
if (objects is [1, "2", ..])
{
Console.WriteLine($"{objects[0]},{objects[1]}");
}
if (objects is [.., string str, Guid guid])
{
Console.WriteLine($"{str},{guid:N}");
}
这段代码等价于:
object[] objects = new object[]
{
1,
"2",
3.0,
"4",
Guid.NewGuid()
};
if (objects != null && objects.Length >= 2 && objects[0] == 1 && objects[1] == "2")
{
Console.WriteLine($"{objects[0]},{objects[1]}");
}
if (objects != null && objects.Length >= 2 && objects[objects.Length-2] is string str && objects[objects.Length-1] is Guid guid)
{
Console.WriteLine($"{str},{guid:N}");
}
除了对于 if
的支持,对于 switch
的匹配也是支持的,示例如下:
var result = objects switch
{
[1, ..] => 1,
[_, "2", ..] => 2,
[_, _, double val, ..] => (int)val,
[.., ""] => 4,
[.., string strVal, Guid _] => Convert.ToInt32(strVal),
_ => -1
};
Console.WriteLine(result);
翻译为普通代码的话会是很长一段的 if ... else
这里就不贴了,感兴趣的可以反编译一下生成的 DLL
More
list pattern 的支持对于模式匹配来说是一个补充,也会让我们的代码写起来更加的简洁
目前匹配的时候 Range 操作符
..
只能在一个模式中出现一次
References
https://github.com/dotnet/csharplang/issues/3435 https://github.com/dotnet/csharplang/blob/main/proposals/list-patterns.md https://github.com/WeihanLi/SamplesInPractice/blob/master/CSharp11Sample/ListPatternSample.cs https://devblogs.microsoft.com/dotnet/early-peek-at-csharp-11-features/
评论