大家好,欢迎来到IT知识分享网。
起因
在C#中模式匹配是通过switch实现的(在c# 7/8是这样的),在C# 7.0新增,在之后C# 7.1/C# 8.0及C# 9.0对模式匹配进行了扩展,模式匹配主要是简化控制流程(看起来和使用起来),让代码有更好的可读性.
最早接触模式匹配,是在Rust语言中,在通过Rust中是用match关键字去实现的.
模式匹配 C# 7.0
/// <summary>
/// 官方文档 示例
/// </summary>
/// <param name="sequence"></param>
/// <returns></returns>
/// <exception cref="NullReferenceException"></exception>
/// <exception cref="InvalidOperationException"></exception>
public static int SumPositiveNumbers(IEnumerable<object> sequence)
{
int sum = 0;
foreach (var i in sequence)
{
switch (i)
{
case 0: //常量
break;
case IEnumerable<int> childSequence: //声明模式 有类型转换 先is 后as进行类型转换
{
foreach (var item in childSequence)
sum += (item > 0) ? item : 0;
break;
}
case int n when n > 0: //进行类型转换
sum += n;
break;
case null:
throw new NullReferenceException("Null found in sequence");
default:
throw new InvalidOperationException("Unrecognized type");
}
}
return sum;
}
模式匹配可以少写一部分代码,看起来跟简单些,让代码具有更强的可读性,其实在C#中的模式匹配,更像语法糖,为什么这么说呢?下面我们一起看反编译工具还原的代码:
ublic static int SumPositiveNumbers(IEnumerable<object> sequence)
{
int num;
int num1 = 0;
IEnumerator<object> enumerator = sequence.GetEnumerator();
try
{
while (true)
{
if (enumerator.MoveNext())
{
object current = enumerator.get_Current();
if (!(current is int)) //判断类型是否为int
{
IEnumerable<int> enumerable = current as IEnumerable<int>;
if (enumerable != null)
{
IEnumerator<int> enumerator1 = enumerable.GetEnumerator();
try
{
while (enumerator1.MoveNext())
{
int current1 = enumerator1.get_Current();
num1 = num1 + (current1 > 0 ? current1 : 0);
}
}
finally
{
if (enumerator1 != null)
{
enumerator1.Dispose();
}
}
}
else
{
if (current == null) //判断为空
{
throw new NullReferenceException("Null found in sequence");
}
break;
}
}
else
{
int num2 = (int)current; //直接进行类型强制转换
if (num2 != 0)
{
if (num2 > 0)
{
num1 += num2;
}
else
{
break;
}
}
}
}
else
{
num = num1;
return num;
}
}
throw new InvalidOperationException("Unrecognized type"); //default 最后处理
}
finally
{
if (enumerator != null)
{
enumerator.Dispose();
}
}
num = num1;
return num;
}
模式匹配增加,增强switch对类型的支持,从早期支持整数/枚举和字符串,到任意类型.
看BenckmarkDotNet源码,是如何使用的:
internal static CoreRuntime FromVersion(Version version)
{
switch (version)
{
case Version v when v.Major == 2 && v.Minor == 0: return Core20;
case Version v when v.Major == 2 && v.Minor == 1: return Core21;
case Version v when v.Major == 2 && v.Minor == 2: return Core22;
case Version v when v.Major == 3 && v.Minor == 0: return Core30;
case Version v when v.Major == 3 && v.Minor == 1: return Core31;
case Version v when v.Major == 5 && v.Minor == 0: return GetPlatformSpecific(Core50);
case Version v when v.Major == 6 && v.Minor == 0: return GetPlatformSpecific(Core60);
case Version v when v.Major == 7 && v.Minor == 0: return GetPlatformSpecific(Core70);
default:
return CreateForNewVersion(#34;net{version.Major}.{version.Minor}", #34;.NET {version.Major}.{version.Minor}");
}
}
BenchmarkDotNet现在是同步支持.Net版本,已经开始支持.Net 7,这和原先是不一样的,因为现在.Net 6已经发布rc1,最近应该发布rc2,下个月要发布正式版,在发布rc1时,代表.Net 6不会增加新的特性,并且新特性都会添加到.Net 7,.Net 7已经进入alpha了.
模式匹配 C# 8.0
在C# 8.0 模式匹配进一步得到了增强,这时候和rust的模式匹配使用很像.主要表现在:
- 增强switch表达式
- 增加属性模式
- 增加元祖模式
- 增加位置模式
public int PatternMatch8(int val) => val switch
{
1 => 10,
2 => 10 * 2,
3 => 10 * 3,
_ => 10 * 10, //_代表弃元 在这里代替default
};
在使用ILSpy反编译工具:
下面看一下属性模式:
/// <summary>
/// 属性模式
/// </summary>
/// <param name="people"></param>
/// <returns></returns>
public decimal PatternMatch8(People people) => people switch
{
{ Name: "tom" } => people.Salary * 1.1m,
{ Name: "jack" } => people.Salary * 1.2m,
_ => 0m
};
位置模式:
public class Point
{
public int X { get; }
public int Y { get; }
public Point(int x, int y) => (X, Y) = (x, y);
public void Deconstruct(out int x, out int y) =>
(x, y) = (X, Y);
}
看一下反编译代码:
看到位置模式,想到两个变量交换:
/// <summary>
/// 变量交换
/// </summary>
public void SwapVal()
{
int a = 10, b = 20;
System.Console.WriteLine(#34;a={a} b={b}");
(a, b) = (b, a); //在c# 8.0,支持这样语法,以后看到这样的语法,不要蒙圈
System.Console.WriteLine(#34;a={a} b={b}");
}
模式匹配 c# 9.0
public bool IsAlpha(char c)
{
return c is >= 'a' and <= 'z' or >= 'A' and <= 'Z';
}
反编译代码:
//dnspy反编译,这个更贴近IL
public bool IsAlpha(char c)
{
if (c >= 'a')
{
if (c > 'z')
{
goto IL_1D;
}
}
else
{
if (c < 'A')
{
goto IL_1D;
}
if (c > 'Z')
{
goto IL_1D;
}
}
return true;
IL_1D:
return false;
}
//ILSpy 反编译
public bool IsAlpha(char c)
{
switch (c)
{
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
case 'G':
case 'H':
case 'I':
case 'J':
case 'K':
case 'L':
case 'M':
case 'N':
case 'O':
case 'P':
case 'Q':
case 'R':
case 'S':
case 'T':
case 'U':
case 'V':
case 'W':
case 'X':
case 'Y':
case 'Z':
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
case 'g':
case 'h':
case 'i':
case 'j':
case 'k':
case 'l':
case 'm':
case 'n':
case 'o':
case 'p':
case 'q':
case 'r':
case 's':
case 't':
case 'u':
case 'v':
case 'w':
case 'x':
case 'y':
case 'z':
return true;
default:
return false;
}
}
这篇文章是国庆后就开始写的,一直没有完成(拖延症),年底了,开始对没有完成的博文进行清零.
龙芯LoongArch .Net编译组已经向.Net社区提交关于.Net 在LoongArch架构代码,在国产CPU个人跟看好LoongArch.尤其是看到Intel致信供应商禁用新疆产品新闻,希望我的下一台电脑是龙芯的,固态硬盘用致钛(长江存储).
个人能力有限,如果您发现有什么不对,请私信我
如果您觉得对您有用的话,可以点个赞或者加个关注,欢迎大家一起进行技术交流
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/13092.html