C#范围表达式,模式匹配,逆变和协变--11

打印 上一主题 下一主题

主题 1042|帖子 1042|积分 3126

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
目录
一.范围表达式
1.概述
2.语法
3.代码示例
 4.实现原理
5.应用场景
二.模式匹配
1.概述
2.核心概念
3.常用模式范例
4.Switch表达式
5.利用示例
6.优势
三.逆变和协变
1.概述
2.泛型范例参数的变性
3.协变示例
4.逆变示例
5.留意事项
6.应用场景
总结


一.范围表达式

1.概述



  • 范围表达式是C# 8.0引入的新特性,它提供了一种简洁的语法来表现数组,字符串或任何实现了索引器的集合范例的子范围(slice).通过范围表达式,可以更方便地从集合中提取出特定范围的元素
2.语法



  • startIndex..endIndex:表现从startIndex开始(包含),到endIndex结束(不包含)的元素
  • ..endIndex:表现从集合的起始位置到endIndex(不包含)的元素
  • startIndex..:表现从startIndex开始(包含)到集合的末尾的所有元素
  • ..:表现集合中的所有元素
   留意:索引可以是正数,也可以是利用^符号表现的从末尾开始的索引,此中^1表现末了一个元素
  3.代码示例

  1. int[] numbers = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
  2.    
  3. // 从索引2(值为2)到索引5(值为5),不包含索引5   
  4. int[] slice1 = numbers[2..5]; // {2, 3, 4}
  5.    
  6. // 从开始到索引3(不包含索引3)   
  7. int[] slice2 = numbers[..3]; // {0, 1, 2}
  8.    
  9. // 从索引5到结尾   
  10. int[] slice3 = numbers[5..]; // {5, 6, 7, 8, 9}
  11.    
  12. // 获取最后两个元素   
  13. int[] slice4 = numbers[^2..]; // {8, 9}
  14.    
  15. // 获取从索引1到倒数第二个元素   
  16. int[] slice5 = numbers[1..^1]; // {1, 2, 3, 4, 5, 6, 7, 8}
复制代码
 4.实现原理

范围表达式利用了System.Index和System.Range结构:


  • Index:表现一个索引位置,可以从开头(从0开始)或从结尾(利用^符号)计数
  • Range:由Index的起始和结束位置构成,表现一个范围
编译器会将范围表达式转换为调用Slice方法或其他适当的方法.比方numbers[2..5]会转换为numbers.Slice(2, 3)
   在C#中,Slice方法是与Span<T>和ReadonlySpan<T>范例相关的功能,用于在不复制数据的情况下生成一个子序列.这种方法在处理大型数据集或须要高性能操作时特别有用,因为它避免了不须要的数据复制
  根本用法:
  1. using System;
  2.    
  3. class Program   
  4. {
  5.     static void Main()
  6.     {
  7.         int[] array = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
  8.         Span<int> span = array; // 创建一个 Span<int> 包含整个数组
  9.         // 从索引2开始,取3个元素
  10.         Span<int> slice = span.Slice(2, 3);
  11.         foreach (var item in slice)
  12.         {
  13.             Console.WriteLine(item); // 输出: 3 4 5
  14.         }
  15.     }   
  16. }
复制代码
5.应用场景



  • 字符串处理:
  1. string text = "Hello, World!";   
  2. string subText = text[7..^1]; // "World"
复制代码


  • 列表和视图:
如果列表实现了Slice方法或索引器支持Range则也可以利用范围表达式
二.模式匹配

1.概述



  • 模式匹配是C#从7.0版本开始引入的特性,用于更简洁地表达范例查抄,解构和条件判断.在C# 8.0及后续版本中,模式匹配得到了进一步增强,使代码更加清晰和易读
2.核心概念



  • 模式(Pattern):描述须要匹配的特定外形或条件,比方范例,值,属性等
  • 表达式(Expression):应用模式匹配的对象或值\
3.常用模式范例

恒值模式:匹配特定的常量值
  1. if (obj is null)
  2. {
  3.    // obj为null
  4. }
复制代码
范例模式:查抄对象是否为特定范例,并举行范例转换
  1. if (obj is string s)
  2. {
  3.    // obj是string类型,且已转换为s
  4. }
复制代码
属性模式:查抄对象的属性是否满足特定条件
  1. if (person is { Age: >= 18 })
  2. {
  3.    // person的Age属性大于等于18
  4. }
复制代码
位置模式:对对象举行解构,并匹配解构后的值
  1. if (point is (0, 0))
  2. {
  3.    // point在原点
  4. }
复制代码
递归模式:在模式中嵌套利用其他模式
  1. if (tree is Node(var left, var right))
  2. {
  3.    // 对左子树和右子树进行处理
  4. }
复制代码
4.Switch表达式

C# 8.0引入了新的Switch表达式,更加简洁:
代码示例:
  1. string GetShapeDescription(Shape shape) => shape switch   
  2. {
  3.     Circle { Radius: var r } => $"这是一个半径为{r}的圆形",
  4.     Rectangle { Width: var w, Height: var h } => $"这是一个宽{w}高{h}的矩形",
  5.     _ => "未知形状"   
  6. };   
复制代码
5.利用示例

范例查抄和转换:
  1. if (obj is int number)
  2. {
  3.     Console.WriteLine($"整数:{number}");
  4. }
复制代码
属性匹配:
  1. if (employee is { Position: "Manager", Salary: > 5000 })
  2. {
  3.    // 匹配职位为Manager且薪水大于5000的员工
  4. }
复制代码
6.优势



  • 增强可读性:使条件判断更加直观
  • 淘汰范例转换代码:自动举行范例转换,淘汰冗余代码
  • 支持复杂条件:可以嵌套和组合多种模式,表达复杂的匹配逻辑
三.逆变和协变

1.概述

协变和逆变用于解决泛型范例在继承关系中的转换问题,重要应用于泛型接口和泛型委托.它们允许你在泛型范例之间举行范例转换,而不须要创建新的范例或举行显式转换


  • 协变(Covariance):允许从派生范例转换为基范例(输出位置)
  • 逆变(Contravariance):允许从基范例转换为派生范例(输入位置)
2.泛型范例参数的变性

在泛型接口或委托中,可以利用out和in关键字来声明范例参数的变性:


  • out:协变范例参数,只能用于返回值(输出)
  • in:逆变范例参数,只能用于参数(输入)
3.协变示例

协变接口:
  1. public interface IEnumerable<out T>
  2. {
  3.     IEnumerator<T> GetEnumerator();
  4. }
复制代码
由于T被声明为out,因此IEnumerable<string>可以赋值给IEnumerable<object>:
  1. IEnumerable<string> strings = new List<string>();
  2. IEnumerable<object> objects = strings; // 合法,协变
复制代码
协变委托:
  1. public delegate T Factory<out T>();
复制代码
利用示例:
  1. Factory<string> stringFactory = () => "Hello";
  2. Factory<object> objectFactory = stringFactory; // 合法,协变
复制代码
4.逆变示例

逆变接口:
  1. public interface IComparer<in T>
  2. {
  3.     int Compare(T x, T y);
  4. }
复制代码
由于T被声明为in,因此IComparer<object>可以赋值给IComparer<string>:
  1. IComparer<object> objectComparer = new MyObjectComparer();
  2. IComparer<string> stringComparer = objectComparer; // 合法,逆变
复制代码
逆变委托:
  1. public delegate void Action<in T>(T item);
复制代码
利用示例:
  1. Action<object> objectAction = obj => Console.WriteLine(obj);
  2. Action<string> stringAction = objectAction; // 合法,逆变
复制代码
5.留意事项



  • 限定:变性只能用于接口和委托的范例参数,且范例参数只能用于输入位置(逆变)或输出位置(协变),不能同时用于输入和输出
  • 类和结构体:泛型类和结构体的范例参数不支持变性
  • 方法范例参数:泛型方法的范例参数也不支持变性
6.应用场景



  • 接口的扩展:通过协变和逆变,可以计划更机动的接口,使之更通用
  • 事件处理程序:在委托中利用变性,可以赋值兼容的委托实例
  • 泛型集合:在处理泛型集适时,可以更方便地举行范例转换
总结



  • 协变实用于从派生范例转换为基范例(范例参数用于输出)
  • 逆变实用于从基范例转换为派生范例(范例参数用于输入)

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

麻花痒

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表