news 2026/9/2 1:31:51

c#311 引用类型 out ref task async

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
c#311 引用类型 out ref task async

c# 基础

值类型 引用类型

引用类型

class object array 接口、委托
保存在堆中

clr

管理堆
.net的核心组件 管 代码执行、内存分配、垃圾回收等

object

所有类的基类
C# 中所有类型(值类型 + 引用类型)的最终基类,任何类型都可以隐式转换为object

接口

实现接口时,例如person类 Person tom=new person()
tom是引用类型

publicinterfaceIPerson{}publicclassPerson:IPerson{}IPersontom=newPerson();// tom是引用类型(指向堆中Person实例)
array

数组 所有数组的基类
创建数组也是引用类型
int[] arr1=new int[2];
arr1[0] 是值类型

引用传递

int[] arr1={1,2,3};
public void play(){
int[] arr1={2,3,4};
Console.WriteLine(“arr1”);//2 3 4
Console.WriteLine(string.Join(" “, arr1)); // 输出:2 3 4
}
Console.WriteLine(“arr1”)//
Console.WriteLine(string.Join(” ", arr1)); //1 2 3

int arr1={1,2,3};
public void play(){
arr1[0]=3;//arr1[0]=3
Console.WriteLine(“arr1[0]”);//3
Console.WriteLine(“arr1”);//3 2 3
Console.WriteLine(string.Join(" ", arr1));////3 2 3
}
Console.WriteLine(“arr1[0]”);//3
Console.WriteLine(“arr1”);// 3 2 3

usingSystem;classArrayRefDemo{// 示例1:方法内重新赋值数组变量staticint[]arr1={1,2,3};// 全局数组staticvoidPlay1(){// 这里是「重新创建了一个新数组」,并让方法内的arr1指向新数组int[]arr1={2,3,4};Console.WriteLine(string.Join(" ",arr1));// 输出:2 3 4}// 示例2:方法内修改数组的元素staticvoidPlay2(){// 这里没有新建数组,而是直接修改「原数组」的第一个元素arr1[0]=3;Console.WriteLine(arr1[0]);// 输出:3Console.WriteLine(string.Join(" ",arr1));// 输出:3 2 3}staticvoidMain(){// 测试示例1Play1();Console.WriteLine(string.Join(" ",arr1));// 输出:1 2 3(原数组没变化)Console.WriteLine("-----分割线-----");// 测试示例2Play2();Console.WriteLine(arr1[0]);// 输出:3(原数组被修改)Console.WriteLine(string.Join(" ",arr1));// 输出:3 2 3}}

值类型

包含:int、float、bool、char、结构体(struct)、枚举(enum)等
保存在栈中 例如int
int num=10;
num=15;
num变成15

值传递

int num=15;
public void play(){
int num=10;
Console.WriteLine(“num”);//num=10
}
Console.WriteLine(“num”);//num=15

装箱

int num=10;
object t;
object j=num;
值类型变成引用类型

int [] arr = new int [2] {10, 20};
object obj = arr [0];

intnum=10;objectj=num;// 装箱:栈的int → 堆的objectint[]arr=newint[2]{10,20};objectobj=arr[0];// 装箱:arr[0]的int值 → 堆的object

拆箱

object t=5;
int num2=5;
int num2=t;
引用类型变成值类型

objectt=5;intnum2=(int)t;// 拆箱:堆的object → 栈的int(必须强转)

数组 array

int[] arr1=new int[1];
float[] arr2=new float[] {1.4f,213.2f,23.1f}

int[]arr1=newint[1];// 声明+初始化(长度1,默认值0)float[]arr2=newfloat[]{1.4f,213.2f,23.1f};// 声明+初始化(指定元素)float[]arr3={1.4f,213.2f};// 简化写法(编译器自动推断)

泛型 List

可以存多个同类型的数据 长度可以动态变化

List<int>numList=newList<int>();numList.Add(1);// 动态添加numList.Add(2);numList.Remove(1);// 动态删除

ref out

核心:传 “变量本身”(栈中的引用 / 值),而非 “变量的值”

int[] or={1,2};
void Modify(int[] arr){
arr=new int[] {5,6};}
Modify(or);// or指向1,2

void Modify2(ref int[] arr){
arr=new int[] {5,6}
}
Modify(of);// or指向5,6
ref /out 都是 “把变量本身传过去,而不是把值传过去”,只是规则不一样。

int[]or={1,2};voidModify(int[]arr){arr=newint[]{5,6};// 改的是方法内的局部引用,原数组不变}Modify(or);// or仍指向{1,2}voidModify2(refint[]arr){arr=newint[]{5,6};// 改的是原变量的引用}Modify2(refor);// or指向{5,6}

ref

ref :你必须先有,我才能改
void RefMethod(ref int[] arr){
arr[0]=10;
}
int ori=new int[1];
RefMethod(ref ori);//ori[0]:10

voidRefMethod(refint[]arr){arr[0]=10;// 改数组内容}int[]original=newint[1];// 必须先初始化RefMethod(reforiginal);

我在方法里改 arr[0] = 直接改你外面的数组
ref
外面必须先初始化(你先开好空间)
我方法里帮你赋值 / 改内容

out

你不用有,我来给你造
void OutMethod(out int[] arr){
arr=new int[1];
arr[0]=20;
}
int[] result;

voidOutMethod(outint[]arr){arr=newint[1];// 必须赋值!arr[0]=20;}int[]result;// 不用初始化OutMethod(outresult);

out
外面不用初始化(你不用准备)
方法里必须给你初始化(我来开空间、第一次赋值)

ref 是:调用方法之前,我自己先把数组初始化好。out 是:调用之前我不用初始化,但是方法里面必须把数组初始化、赋值好。

声明 初始化 赋值

int[] arr; → 只声明,没初始化
int[] arr = {1,2,3}; → 声明 + 初始化
arr[0] = 10; → 这是赋值

.NET框架

包含:类库(System、System.IO等)、CLR、编译器等
作用:C# 代码运行的基础体系,屏蔽底层系统差异(跨平台

Task

Task 就是帮你 “后台干活” 的工具,比如上位机读取串口数据可能要等设备响应,用 Task 处理这个过程,界面就不会卡住,用户还能拖动窗口、点击按钮

async

async 是 C# 里用来声明异步方法的关键字,和 Task 配合用。比如你写一个异步读取串口数据的方法,就可以加 async 修饰,里面用 await 调用 Task 相关的异步操作,这样方法执行到耗时步骤时不会阻塞主线程。上位机里写界面响应的方法时,用 async 能让操作更流畅。

// 异步读取串口数据,UI不卡privateasyncvoidbtnReadSerial_Click(objectsender,EventArgse){stringdata=awaitTask.Run(()=>{// 耗时操作:读取串口数据returnserialPort.ReadLine();});txtContent.Text=data;// 任务完成后更新UI}

实例

“实例” 可以理解为根据一个 “模板” 创建出来的具体对象。这里的ModbusSerialMaster.CreateRtu(serialPort)就是用ModbusSerialMaster这个 “模板”,结合已打开的串口serialPort,创建出一个能和 Modbus 设备通信的具体 “工具”,这个 “工具” 就是master实例,后面读取寄存器、线圈的ReadHoldingRegistersAsync等方法,都是通过这个master实例来调用的

// ModbusSerialMaster是类(模板)// master是实例(具体工具),能调用Modbus通信方法varmaster=ModbusSerialMaster.CreateRtu(serialPort);// 调用实例方法:读取保持寄存器varregisters=awaitmaster.Read

var

var是 “隐式类型”,编译器会根据等号右边的内容自动判断它的具体类型。这里var series01 = new LineSeries(),右边是LineSeries,所以series01实际就是LineSeries类型,和写LineSeries series01 = new LineSeries()效果一样,只是用var写起来更简洁。三条曲线用var定义,本质上都是LineSeries对象,所以能被添加到图表的Series集合里,最终显示成曲线。

enum

enum是枚举类型,用来定义一组有名字的常量,让代码更易读。比如你这项目如果有灯光状态,可定义enum LightState { On=1, Off=0 },代替直接写 1 和 0,别人一看就知道 On 代表开。你代码里控制灯光用bool,如果状态更多,enum 会更合适。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/14 17:27:49

为什么放弃 ChatGPT 客户端,选择 OpenClaw 做你的全能业务网关?

一、 引言&#xff1a;你的 AI 生产力&#xff0c;正在被“聊天框”封印 现象剖析 回想一下你每天使用 ChatGPT Web 客户端的场景&#xff1a;你需要手动将数据从 Excel 复制出来&#xff0c;粘贴到对话框里&#xff1b;聊了几天后&#xff0c;AI 开始频繁遗忘早期设定的背景&a…

作者头像 李华
网站建设 2026/7/14 17:28:00

Python基于flask+uniapp微信小程序的校园跑腿帮任务接单互助系统

目录系统架构设计功能模块划分接单与交易流程即时通讯实现支付系统集成地图与定位服务数据库设计安全防护措施测试与部署方案项目技术支持可定制开发之功能创新亮点源码获取详细视频演示 &#xff1a;文章底部获取博主联系方式&#xff01;同行可合作系统架构设计 后端采用Fla…

作者头像 李华
网站建设 2026/7/14 17:28:02

docker 实现ES+Kibana

直接拉取elasticsearch命令&#xff1a;docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.typesingle-node" dhi.io/elasticsearch:7.6.2但启动时linux 可能会卡&#xff0c;可以通过 docker stats 查看 cpu的状态docker stats 通过curl…

作者头像 李华
网站建设 2026/7/14 17:27:50

ATE芯片测试(一)半导体物理基础与ATE测试定位

半导体物理基础与ATE测试定位 1.1 PN结原理与测试应用 PN结作为半导体器件的核心理论基础&#xff0c;其工作原理直接决定了ATE测试的诸多方法。PN结由P型半导体&#xff08;掺杂受主杂质如硼&#xff0c;产生大量空穴&#xff09;和N型半导体&#xff08;掺杂施主杂质如磷&…

作者头像 李华
网站建设 2026/7/14 17:28:03

ARM64地址空间详解

ARM64地址空间详解&#xff1a;VA_BITS vs PA_BITS你有没有想过&#xff1a;为什么32GB的物理内存&#xff0c;设备MMIO地址却可能在64GB甚至更高&#xff1f;&#x1f4da; 概述 本文解决什么问题&#xff1f; ❓ 为什么有32GB物理内存&#xff0c;但设备MMIO地址可能在64GB甚…

作者头像 李华