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

news2025/1/13 19:21:40

目录

一.范围表达式

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.代码示例

int[] numbers = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
   
// 从索引2(值为2)到索引5(值为5),不包含索引5   
int[] slice1 = numbers[2..5]; // {2, 3, 4}
   
// 从开始到索引3(不包含索引3)   
int[] slice2 = numbers[..3]; // {0, 1, 2}
   
// 从索引5到结尾   
int[] slice3 = numbers[5..]; // {5, 6, 7, 8, 9}
   
// 获取最后两个元素   
int[] slice4 = numbers[^2..]; // {8, 9}
   
// 获取从索引1到倒数第二个元素   
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>类型相关的功能,用于在不复制数据的情况下生成一个子序列.这种方法在处理大型数据集或需要高性能操作时特别有用,因为它避免了不必要的数据复制

基本用法:

using System;
   
class Program   
{
    static void Main()
    {
        int[] array = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
        Span<int> span = array; // 创建一个 Span<int> 包含整个数组

        // 从索引2开始,取3个元素
        Span<int> slice = span.Slice(2, 3);
        foreach (var item in slice)
        {
            Console.WriteLine(item); // 输出: 3 4 5
        }
    }   
}

5.应用场景

  • 字符串处理:
string text = "Hello, World!";   
string subText = text[7..^1]; // "World"
  • 列表和视图:

如果列表实现了Slice方法或索引器支持Range则也可以使用范围表达式

二.模式匹配

1.概述

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

2.核心概念

  • 模式(Pattern):描述需要匹配的特定形状或条件,例如类型,值,属性等
  • 表达式(Expression):应用模式匹配的对象或值\

3.常用模式类型

恒值模式:匹配特定的常量值

if (obj is null)
{
   // obj为null
}

类型模式:检查对象是否为特定类型,并进行类型转换

if (obj is string s)
{
   // obj是string类型,且已转换为s
}

属性模式:检查对象的属性是否满足特定条件

if (person is { Age: >= 18 })
{
   // person的Age属性大于等于18
}

位置模式:对对象进行解构,并匹配解构后的值

if (point is (0, 0))
{
   // point在原点
}

递归模式:在模式中嵌套使用其他模式

if (tree is Node(var left, var right))
{
   // 对左子树和右子树进行处理
}

4.Switch表达式

C# 8.0引入了新的Switch表达式,更加简洁:

代码示例:

string GetShapeDescription(Shape shape) => shape switch   
{
    Circle { Radius: var r } => $"这是一个半径为{r}的圆形",
    Rectangle { Width: var w, Height: var h } => $"这是一个宽{w}高{h}的矩形",
    _ => "未知形状"    
};    

5.使用示例

类型检查和转换:

 if (obj is int number)
 {
    Console.WriteLine($"整数:{number}");
 }

属性匹配:

if (employee is { Position: "Manager", Salary: > 5000 })
{
   // 匹配职位为Manager且薪水大于5000的员工
}

6.优势

  • 增强可读性:使条件判断更加直观
  • 减少类型转换代码:自动进行类型转换,减少冗余代码
  • 支持复杂条件:可以嵌套和组合多种模式,表达复杂的匹配逻辑

三.逆变和协变

1.概述

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

  • 协变(Covariance):允许从派生类型转换为基类型(输出位置)
  • 逆变(Contravariance):允许从基类型转换为派生类型(输入位置)

2.泛型类型参数的变性

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

  • out:协变类型参数,只能用于返回值(输出)
  • in:逆变类型参数,只能用于参数(输入)

3.协变示例

协变接口:

public interface IEnumerable<out T>
 {
    IEnumerator<T> GetEnumerator();
 }

由于T被声明为out,因此IEnumerable<string>可以赋值给IEnumerable<object>:

IEnumerable<string> strings = new List<string>();
IEnumerable<object> objects = strings; // 合法,协变

协变委托:

public delegate T Factory<out T>();

使用示例:

Factory<string> stringFactory = () => "Hello";
Factory<object> objectFactory = stringFactory; // 合法,协变

4.逆变示例

逆变接口:

public interface IComparer<in T>
 {
    int Compare(T x, T y);
 }

由于T被声明为in,因此IComparer<object>可以赋值给IComparer<string>:

IComparer<object> objectComparer = new MyObjectComparer();
IComparer<string> stringComparer = objectComparer; // 合法,逆变

逆变委托:

public delegate void Action<in T>(T item);

使用示例:

Action<object> objectAction = obj => Console.WriteLine(obj);
Action<string> stringAction = objectAction; // 合法,逆变

5.注意事项

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

6.应用场景

  • 接口的扩展:通过协变和逆变,可以设计更灵活的接口,使之更通用
  • 事件处理程序:在委托中使用变性,可以赋值兼容的委托实例
  • 泛型集合:在处理泛型集合时,可以更方便地进行类型转换

总结

  • 协变适用于从派生类型转换为基类型(类型参数用于输出)
  • 逆变适用于从基类型转换为派生类型(类型参数用于输入)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2276107.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

springboot 默认的 mysql 驱动版本

本案例以 springboot 3.1.12 版本为例 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.1.12</version><relativePath/> </parent> 点击 spring-…

[QCustomPlot] 交互示例 Interaction Example

本文是官方例子的分析: Interaction Example 推荐笔记: qcustomplot使用教程–基本绘图 推荐笔记: 4.QCustomPlot使用-坐标轴常用属性 官方例子需要用到很多槽函数, 这里先一次性列举, 自行加入到qt的.h中.下面开始从简单的开始一个个分析. void qcustomplot_main_init(void); …

openMetaData docker方式安装部署记录

OpenMetadata一站式元数据管理平台&#xff0c;是一款功能强大的开源元数据管理平台&#xff0c;旨在帮助企业更好地发现、理解和管理其数据资产。它提供了一套全面的工具和功能&#xff0c;涵盖了数据发现、数据血缘、数据质量、数据探查、数据治理和团队协作等多个方面。 那…

57. Three.js案例-创建一个带有聚光灯和旋转立方体的3D场景

57. Three.js案例-创建一个带有聚光灯和旋转立方体的3D场景 实现效果 该案例实现了使用Three.js创建一个带有聚光灯和旋转立方体的3D场景。 知识点 WebGLRenderer&#xff08;WebGL渲染器&#xff09; THREE.WebGLRenderer 是 Three.js 中用于将场景渲染为 WebGL 内容的核…

本地视频进度加入笔记+根据进度快速锁定视频位置

本地视频进度记录快速回溯 引言 在学习的过程中, 如果我们想快速记录当前看视频的位置, 后续回溯查找就会非常方便了。 实现效果 进度记录 通过按下快捷键ctrlaltu&#xff0c; 快速记录当前视频的进度信息,然后复制到typora软件内 快速回溯 在typora软件内, 选中视频索引…

Spring Boot 支持哪些日志框架

Spring Boot 支持多种日志框架&#xff0c;主要包括以下几种&#xff1a; SLF4J (Simple Logging Facade for Java) Logback&#xff08;默认&#xff09;Log4j 2Java Util Logging (JUL) 其中&#xff0c;Spring Boot 默认使用 SLF4J 和 Logback 作为日志框架。如果你需要使…

快速导入请求到postman

1.确定请求&#xff0c;右键复制为cURL(bash) 2.postman菜单栏Import-Raw text&#xff0c;粘贴复制的内容保存&#xff0c;请求添加成功

Golang的网络流量分配策略

## 1. Golang中的网络流量分配策略 简介 在Golang中&#xff0c;网络流量分配策略是指如何有效地管理和优化网络请求的分配&#xff0c;以提高系统的性能和稳定性。优秀的网络流量分配策略能够使系统更好地应对高并发和大流量的情况&#xff0c;同时有效地避免网络拥堵和性能瓶…

【硬件介绍】Type-C接口详解

一、Type-C接口概述 Type-C接口特点&#xff1a;以其独特的扁头设计和无需区分正反两面的便捷性而广受欢迎。这种设计大大提高了用户的使用体验&#xff0c;避免了传统USB接口需要多次尝试才能正确插入的问题。Type-C接口内部结构&#xff1a;内部上下两排引脚的设计虽然可能不…

二、BIO、NIO编程与直接内存、零拷贝

一、网络通信 1、什么是socket&#xff1f; Socket 是应用层与 TCP/IP 协议族通信的中间软件抽象层&#xff0c;它是一组接口&#xff0c;一般由操作 系统提供。客户端连接上一个服务端&#xff0c;就会在客户端中产生一个 socket 接口实例&#xff0c;服务端每接受 一个客户端…

Android车机DIY开发之软件篇(九)默认应用和服务修改

Android车机DIY开发之软件篇(九)默认应用和服务修改 默认应用位置 ~/packages/apps/Car 增加APP 1.增加 XXXX.app 和Android.mk 2. 修改~/build/make/target/product/handheld_system_ext.mk 默认服务位置 ~/frameworks/base/services/java/com/android/server 查看服务列…

【Rust】错误处理机制

目录 思维导图 引言 一、错误处理的重要性 1.1 软件中的错误普遍存在 1.2 编译时错误处理要求 二、错误的分类 2.1 可恢复错误&#xff08;Recoverable Errors&#xff09; 2.2 不可恢复错误&#xff08;Unrecoverable Errors&#xff09; 三、Rust 的错误处理机制 3…

DDD - 微服务设计与领域驱动设计实战(上)_统一建模语言及事件风暴会议

文章目录 Pre概述业务流程需求分析的困境统一语言建模事件风暴会议什么是事件风暴&#xff08;Event Storming&#xff09;事件风暴会议 总结 Pre DDD - 软件退化原因及案例分析 DDD - 如何运用 DDD 进行软件设计 DDD - 如何运用 DDD 进行数据库设计 DDD - 服务、实体与值对…

用HTML + CSS实现太极图

目录 一、效果图 二、实现思路 三、完整代码 四、总结 一、效果图 如图所示&#xff0c;太极图一半为黑色&#xff08;代表阴&#xff09;&#xff0c;另一半为白色&#xff08;代表阳&#xff09;。这两部分相互环绕&#xff0c;形成一种流动的、旋转的感觉。 二、实现思…

Apache Hadoop YARN框架概述

一、YARN产生和发展简史 1.1背景 数据、程序、运算资源&#xff08;内存、CPU&#xff09;三者组在一起&#xff0c;才能完成数据的计算处理过程。在单机环境下&#xff0c;三者之间协调配合不是太大问题。为了应对海量数据的处理场景&#xff0c;Hadoop软件出现并提供了分布…

一个个顺序挨着来 - 责任链模式(Chain of Responsibility Pattern)

责任链模式&#xff08;Chain of Responsibility Pattern&#xff09; 责任链模式&#xff08;Chain of Responsibility Pattern&#xff09;责任链模式&#xff08;Chain of Responsibility Pattern&#xff09;概述责任链结构图责任链模式概述责任链模式涉及的角色 talk is c…

.NET framework、Core和Standard都是什么?

对于这些概念一直没有深入去理解&#xff0c;以至于经过.net这几年的发展进化&#xff0c;概念越来越多&#xff0c;越来越梳理不容易理解了。内心深处存在思想上的懒惰&#xff0c;以为自己专注于Unity开发就好&#xff0c;这些并不属于核心范畴&#xff0c;所以对这些概念总是…

【Java回顾】Day5 并发基础|并发关键字|JUC全局观|JUC原子类

JUC全称java.util.concurrent 处理并发的工具包(线程管理、同步、协调) 一.并发基础 多线程要解决什么问题&#xff1f;本质是什么&#xff1f; CPU、内存、I/O的速度是有极大差异的&#xff0c;为了合理利用CPU的高性能&#xff0c;平衡三者的速度差异&#xff0c;解决办法…

android framework.jar 在应用中使用

在开发APP中&#xff0c;有时会使用系统提供的framework.jar 来替代 android.jar, 在gradle中配置如下&#xff1a; 放置framework.jar 依赖配置 3 优先级配置 gradle.projectsEvaluated {tasks.withType(JavaCompile) {Set<File> fileSet options.bootstrapClasspat…

CHAIN OF RESPONSIBILITY(职责链)—对象行为型模式

1. 意图 使多个对象都有机会处理请求&#xff0c;从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链&#xff0c;并沿着这条链传递该请求&#xff0c;直到有一个对象处理它为止。 2. 动机 考虑一个图形用户界面中的上下文有关的帮助机制。用户在界面的任一部分…