c#311 引用类型 out ref task async

c# 基础

值类型 引用类型

引用类型

class object array 接口、委托

保存在堆中

clr

管理堆

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

object

所有类的基类

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

接口

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

tom是引用类型

csharp 复制代码
public interface IPerson { }
public class Person : IPerson { }
IPerson tom = new Person(); // 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

csharp 复制代码
using System;

class ArrayRefDemo
{
    // 示例1:方法内重新赋值数组变量
    static int[] arr1 = { 1, 2, 3 }; // 全局数组
    static void Play1()
    {
        // 这里是「重新创建了一个新数组」,并让方法内的arr1指向新数组
        int[] arr1 = { 2, 3, 4 }; 
        Console.WriteLine(string.Join(" ", arr1)); // 输出:2 3 4
    }

    // 示例2:方法内修改数组的元素
    static void Play2()
    {
        // 这里没有新建数组,而是直接修改「原数组」的第一个元素
        arr1[0] = 3; 
        Console.WriteLine(arr1[0]); // 输出:3
        Console.WriteLine(string.Join(" ", arr1)); // 输出:3 2 3
    }

    static void Main()
    {
        // 测试示例1
        Play1();
        Console.WriteLine(string.Join(" ", arr1)); // 输出:1 2 3(原数组没变化)
        
        Console.WriteLine("-----分割线-----");
        
        // 测试示例2
        Play2();
        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];

csharp 复制代码
int num = 10;
object j = num; // 装箱:栈的int → 堆的object
int[] arr = new int[2] { 10, 20 };
object obj = arr[0]; // 装箱:arr[0]的int值 → 堆的object

拆箱

object t=5;

int num2=5;

int num2=t;

引用类型变成值类型

csharp 复制代码
object t = 5;
int num2 = (int)t; // 拆箱:堆的object → 栈的int(必须强转)

数组 array

int[] arr1=new int[1];

float[] arr2=new float[] {1.4f,213.2f,23.1f}

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

泛型 List

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

csharp 复制代码
List<int> numList = new List<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 都是 "把变量本身传过去,而不是把值传过去",只是规则不一样。

csharp 复制代码
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 }; // 改的是原变量的引用
}
Modify2(ref or); // or指向{5,6}

ref

ref :你必须先有,我才能改

void RefMethod(ref int[] arr){

arr[0]=10;

}

int ori=new int[1];

RefMethod(ref ori);//ori[0]:10

csharp 复制代码
void RefMethod(ref int[] arr)
{
    arr[0] = 10;       // 改数组内容
}

int[] original = new int[1];  // 必须先初始化
RefMethod(ref original);

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

out

你不用有,我来给你造

void OutMethod(out int[] arr){

arr=new int[1];

arr[0]=20;

}

int[] result;

csharp 复制代码
void OutMethod(out int[] arr)
{
    arr = new int[1];   // 必须赋值!
    arr[0] = 20;
}

int[] result;  // 不用初始化
OutMethod(out result);

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 能让操作更流畅。

csharp 复制代码
// 异步读取串口数据,UI不卡
private async void btnReadSerial_Click(object sender, EventArgs e)
{
    string data = await Task.Run(() => 
    {
        // 耗时操作:读取串口数据
        return serialPort.ReadLine();
    });
    txtContent.Text = data; // 任务完成后更新UI
}

实例

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

csharp 复制代码
// ModbusSerialMaster是类(模板)
// master是实例(具体工具),能调用Modbus通信方法
var master = ModbusSerialMaster.CreateRtu(serialPort);
// 调用实例方法:读取保持寄存器
var registers = await master.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 会更合适。

相关推荐
未来之窗软件服务21 小时前
幽冥大陆(一百12)js打造json硬件管道——东方仙盟筑基期
开发语言·javascript·算法·json·仙盟创梦ide·东方仙盟·东方仙盟算法
人道领域21 小时前
苍穹外卖:菜品分页查询与删除功能(保姆级详解)
java·开发语言·数据库·后端·spring
EverestVIP21 小时前
c++前置声明的方式与说明
开发语言·c++
CSharp精选营21 小时前
.NET命名之谜:它与C#纠缠20年的关系揭秘
c#·.net·dotnet·csharp
是五月吖21 小时前
【C#】SOLID原则
c#
就是有点傻21 小时前
如何使用简单的服务端去接收数据
c#
天远云服1 天前
天远企业司法认证API对接实战:PHP构建B2B供应链合规防火墙
大数据·开发语言·后端·node.js·php
空空kkk1 天前
Java基础——代理
java·开发语言
赵谨言1 天前
基于YOLOv5的植物目标检测研究
大数据·开发语言·经验分享·python
野生技术架构师1 天前
互联网大厂必备 Java 面试八股文真题解析
java·开发语言·面试