当前位置: 首页 > news >正文

【C#学习笔记】值类型(2)

在这里插入图片描述

文章目录

  • Struct结构体类型
    • 为什么不推荐struct
  • 元组类型
  • 可为空的值类型
    • 从可为空的值类型转换为基础类型
    • 提升的运算符
    • 如何确定可为空的值类型
    • 为什么建议少用`T?`
      • 装箱和取消装箱


Struct结构体类型

结构类型(“structure type”或“struct type”)是一种可封装数据和相关功能的值类型 。 使用 struct 关键字定义结构类型:

public struct Coords
{public Coords(double x, double y){X = x;Y = y;}public double X { get; }public double Y { get; }public override string ToString() => $"({X}, {Y})";
}

结构类型具有值语义 。 也就是说,结构类型的变量包含类型的实例。 默认情况下,在分配中,通过将参数传递给方法并返回方法结果来复制变量值。 对于结构类型变量,将复制该类型的实例。

使用readonly关键字来保证结构体状态不可变。以此保证结构体内的成员不会修改结构体本身状态。正是由于它是值类型的,因此有可能会被修改,而我们又不希望它被修改。

为什么不推荐struct

这里也要点出为什么class往往优于struct,因为结构体是值类型的,一方面,结构体的赋值是通过复制整个结构体的值来实现的。这意味着当结构体的值较大时,赋值操作需要复制较多的数据,可能会消耗大量的内存和时间。

另一方面,结构体在作为参数传递给方法时,会进行值传递。这意味着传递的是结构体的一个副本,而不是原始的结构体实例。这会导致在方法内对结构体的修改不会影响到原始实例。

相比之下,使用类作为引用类型可以避免上述问题。类对象的赋值和传递只涉及引用的复制,而不是整个对象的复制。这样可以避免不必要的内存和时间消耗。而且类对象的传递是引用传递,这意味着方法内对对象的修改会影响到原始实例。

而一切的缺陷,本质根源于结构体是一个值类型,而class是引用类型。


元组类型

元组功能提供了简洁的语法来将多个数据元素分组成一个轻型数据结构。 下面的示例演示了如何声明元组变量、对它进行初始化并访问其数据成员:

(double, int) t1 = (4.5, 3);
Console.WriteLine($"Tuple with elements {t1.Item1} and {t1.Item2}.");
// Output:
// Tuple with elements 4.5 and 3.(double Sum, int Count) t2 = (4.5, 3);
Console.WriteLine($"Sum of {t2.Count} elements is {t2.Sum}.");
// Output:
// Sum of 3 elements is 4.5.

若要定义元组类型,需要指定其所有数据成员的类型,或者,可以指定字段名称。 虽然不能在元组类型中定义方法,但可以使用 .NET 提供的方法,如下面的示例所示:

(double, int) t = (4.5, 3);
Console.WriteLine(t.ToString());
Console.WriteLine($"Hash code of {t} is {t.GetHashCode()}.");
// Output:
// (4.5, 3)
// Hash code of (4.5, 3) is 718460086.

使用元组类型的情况通常用于接受函数多返回值。如果想要一个可变动的,带有方法的数据结构,类还是优于元组的。


可为空的值类型

在值类型的变量中,大部分值是不允许为空的,因此我们可以使用Nullable<T>T?定义可为空的值类型。但基础值类型 T 本身不能是可为空的值类型。

需要表示基础值类型的未定义值时,通常使用可为空的值类型。 例如,布尔值或 bool 变量只能为 true 或 false。 但是,在某些应用程序中,变量值可能未定义或缺失。 例如,某个数据库字段可能包含 true 或 false,或者它可能不包含任何值,即 NULL。 在这种情况下,可以使用 bool? 类型。

也就是说,当我们需要一个不可为空的值,而实际情况下可能会出现为空值的情况,我们就需要用到T?

由于值类型可隐式转换为相应的可为空的值类型,因此可以像向其基础值类型赋值一样,向可为空值类型的变量赋值。 还可分配 null 值。 例如:

double? pi = 3.14;
char? letter = 'a';int m2 = 10;
int? m = m2;bool? flag = null;// An array of a nullable value type:
int?[] arr = new int?[10];

可为空值类型的默认值表示 null,也就是说,它是其 Nullable<T>.HasValue 属性返回 false 的实例。

通常判断可为空值内是否为空有三种做法:

int? a = 42;
if (a is int valueOfA) // valueOfA代表A的ASCII码对应值
{
}
if (a is null)
{
}
或者
if (a.HasValue)
{
}
或者
if (a != null)
{
}

从可为空的值类型转换为基础类型

如果要将可为空值类型的值分配给不可以为 null 的值类型变量,则可能需要指定要分配的替代 null 的值。

int? a = 28;
-- 使用??操作符,使用方法是a = x ?? y 或x ??= y
-- a = x??y当x为空,则a=y ,x非空则a= x
-- x??= y当x为空则x=y,非空则不处理
int b = a ?? -1;
Console.WriteLine($"b is {b}");  // output: b is 28int? c = null;
int d = c ?? -1;
Console.WriteLine($"d is {d}");  // output: d is -1

注意,实际上TT?不是同一种值类型,所以同为值类型如果使用强制转换是可以的,但是如果把一个空值转换给一个非空类型是会报错的:

int? n = null;//int m1 = n;    // Doesn't compile
int n2 = (int)n; // Compiles, but throws an exception if n is null

提升的运算符

任何T类型本身所支持的运算符,如果在运算时带有了T?类型,那么运算也是可以正常运行的。这些运算符将被提升,而运算结果将变为可为空值,但是类型还是需要符合T运算时的类型转换(例如int+float=浮点型,所以int?+folat?=浮点型?)。

int? a = 10;
float? b = null;
double? c = 0;c = a + b;  // a is null
print(c); --Null

而bool值的计算稍微特殊,总体上也是符合bool运算法则的(我在lua学习笔记中总结了Lua入门):

bool? a = true;
bool? b = null;
bool? c = true;
c = a & b;
Debug.Log(c); --null
c = a | b;
Debug.Log(c); --true

对于比较运算符<、>、<= 和 >=,如果一个或全部两个操作数都为 null,则结果为 false;否则,将比较操作数的包含值。而带有null值时唯一可以进行比较运算的只有==!=

int? a = 10;
Console.WriteLine($"{a} >= null is {a >= null}");
Console.WriteLine($"{a} < null is {a < null}");
Console.WriteLine($"{a} == null is {a == null}");
// Output:
// 10 >= null is False
// 10 < null is False
// 10 == null is Falseint? b = null;
int? c = null;
Console.WriteLine($"null >= null is {b >= c}");
Console.WriteLine($"null == null is {b == c}");
// Output:
// null >= null is False
// null == null is True

如何确定可为空的值类型

IsNullable(typeof(T?))

Console.WriteLine($"int? is {(IsNullable(typeof(int?)) ? "nullable" : "non nullable")} value type");
Console.WriteLine($"int is {(IsNullable(typeof(int)) ? "nullable" : "non-nullable")} value type");bool IsNullable(Type type) => Nullable.GetUnderlyingType(type) != null;// Output:
// int? is nullable value type
// int is non-nullable value type

在获取可为空的值类型的时候,注意只能使用typeof()不能使用GetType(),后者只能返回基类的类型:

int? a = 17;
Type typeOfA = a.GetType();
Console.WriteLine(typeOfA.FullName);
// Output:
// System.Int32

此外,is关键字无法判断 TT?,默认它们是同类型

int? a = 42;
if (a is int valueOfA)
{print(a); --结果打印 42
}

为什么建议少用T?

T?虽然可以避免值类型接受空值,但是我们应该尽量避免使用T?,这是因为这个类型实际上是对T类型的装箱和拆箱。当我们声明这个变量的时候,它会被编译器装箱为T?,而当我们操作T?的时候编译器又会对它拆箱,实际上它像是一个拥有T和另一个变量Null的类。为了避免装箱拆箱操作对内存的影响,能不用尽量不用。

装箱和取消装箱

由于 T?已装箱,因此如果我们再对其装箱则会产生以下的情况判断:

  • 如果 HasValue 返回 false,则生成空引用。
  • 如果 HasValue 返回 true,则基础值类型 T 的对应值将装箱,而不对 Nullable<T> 的实例进行装箱。(也就是重新对T类型的对应值装箱一次)

可将值类型 T 的已装箱值取消装箱到相应的可为空值类型 T?,如以下示例所示:

int a = 41;
object aBoxed = a; 
int? aNullable = (int?)aBoxed; -- 把已装箱的a取消装箱并重新装箱为int?
Console.WriteLine($"Value of aNullable: {aNullable}");object aNullableBoxed = aNullable;   -- HasValue=true,则基础类型int将重新被装箱
if (aNullableBoxed is int valueOfA)
{Console.WriteLine($"aNullableBoxed is boxed int: {valueOfA}");
}int? b = null;
object aNullableBoxed = b;   -- HasValue=false,则生成空引用
if (aNullableBoxed == null)
{Console.WriteLine($"aNullableBoxed is boxed int: {valueOfA}");
}
// Output:
// Value of aNullable: 41
// aNullableBoxed is boxed int: 41
// aNullableBoxed is boxed int: 41

相关文章:

【C#学习笔记】值类型(2)

文章目录 Struct结构体类型为什么不推荐struct 元组类型可为空的值类型从可为空的值类型转换为基础类型提升的运算符如何确定可为空的值类型为什么建议少用T?装箱和取消装箱 Struct结构体类型 结构类型&#xff08;“structure type”或“struct type”&#xff09;是一种可封…...

【设计模式】-建造者模式

Java建造者模式&#xff1a;创建复杂对象的灵活构建者 在软件开发中&#xff0c;我们经常遇到需要创建一个复杂对象的情况。如果使用传统的构造函数进行对象创建&#xff0c;可能会导致构造函数参数过多&#xff0c;难以管理和维护。建造者模式&#xff08;Builder Pattern&am…...

【N32L40X】学习笔记14-在RT-thread系统中读取eeprom数据

eeprom 说明 eeprom介绍 AT24C01A&#xff0c;1K串行EEPROM&#xff1a;内部组织16页8字节&#xff0c;1K需要一个7位数据字地址进行随机字寻址。AT24C02,2K串行EEPROM&#xff1a;内部组织32页8字节&#xff0c;2K需要一个8位数据字地址进行随机字寻址。AT24C04,4K串行EEPRO…...

Python OpenCV读取并显示USB UVC摄像头

1. 安装Python&#xff0c; 略。 2. 安装 OpenCV: pip install opencv-python 3. 预览摄像头画面脚本&#xff1a; import cv2cap cv2.VideoCapture(0, cv2.CAP_DSHOW)if not (cap.isOpened()):print("Could not open video device")cap.set(cv2.CAP_PR…...

针对高可靠性和高性能优化的1200V碳化硅沟道MOSFET

目录 标题&#xff1a;1200V SiC Trench-MOSFET Optimized for High Reliability and High Performance摘要信息解释研究了什么文章创新点文章的研究方法文章的结论 标题&#xff1a;1200V SiC Trench-MOSFET Optimized for High Reliability and High Performance 摘要 本文详…...

在服务器上搭建gitlab

最终效果展示&#xff1a; 官方文档&#xff1a; 安装部署GitLab服务 1.在服务器上下载gitlab wget https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el7/gitlab-ce-12.9.0-ce.0.el7.x86_64.rpm rpm -ivh gitlab-ce-12.9.0-ce.0.el7.x86_64.rpm 2.编辑站点位置 vim …...

Amazon Aurora Serverless v2 正式发布:针对要求苛刻的工作负载的即时扩展

我们非常兴奋地宣布&#xff0c;Amazon Aurora Serverless v2 现已面向 Aurora PostgreSQL 和 MySQL 正式发布。Aurora Serverless 是一种面向 Amazon Aurora 的按需自动扩展配置&#xff0c;可让您的数据库根据应用程序的需求扩展或缩减容量。 亚马逊云科技开发者社区为开发者…...

nginx的优化和防盗链 重要!!!

实验一、隐藏版本号 要把nginx的版本号隐藏起来&#xff0c;防止恶意攻击 方法一&#xff1a;修改配置文件 在http模块中加入一个命令 server_token off&#xff1b; 过程&#xff1a; 备份&#xff0c;改配置文件一定要备份 修改配置文件 在http模块中添加 server_tokens …...

十五.redis缓存穿透,击穿,雪崩

redis哨兵模式 一.缓存穿透1.概念2.解决方案1&#xff09;接口校验2&#xff09;缓存空值3&#xff09;布隆过滤器4&#xff09;实时监控 二.缓存击穿1.概念2.解决方案1&#xff09;设置热点数据永不过期2&#xff09;加互斥锁3&#xff09;”提前“使用互斥锁 / 逻辑过期4&…...

Spring源码——初识Spring容器

Spring源码之工厂&#xff08;容器&#xff09; 为什么把Spring的工厂又叫做容器呢&#xff1f; 工厂的责任是创建对象&#xff0c;但是创建完对象后还要进行存储&#xff08;针对于单例的对象来讲&#xff09;&#xff0c;以供其他地方使用&#xff0c;这就是容器。为了能存…...

arcgis--数据库构建网络数据集

1、打开arcmap软件&#xff0c;导入数据&#xff0c;如下&#xff1a; 该数据已经过处理&#xff0c;各交点处均被打断&#xff0c;并进行了拓扑检查。 2、在文件夹下新建文件数据库&#xff0c;名称为路网&#xff0c;在数据库下新建要素类&#xff0c;并导入道路shp文件&…...

华为OD机试真题【西天取经】

1、题目描述 【西天取经】 唐僧师徒四人去西天取经&#xff0c;一路翻山越岭。一日&#xff0c;师徒四人途径一个 mxn 长方形区域&#xff0c;已知 1.将取经队伍作为一个整体&#xff0c;4 人行走相同路线。 2.取经队伍的起点为该长方形区域的左上角&#xff0c;目的地为该长方…...

心电信号时域特征分析与Python实现

目录 1 引言 2 心电信号时域特征的含义 3 Python实现心电信号时域特征提取 4 结论 1 引言 心电信号是由心脏电活动引起的电信号...

认识MyBatis 之 MyBatis的动态SQL

前言 本篇介绍MyBatis里如何使用动态SQL&#xff0c;了解如何去简单使用动态标签&#xff1b;如有错误&#xff0c;请在评论区指正&#xff0c;让我们一起交流&#xff0c;共同进步&#xff01; 文章目录 前言MyBatis - 动态 SQLif标签trim标签where标签update set 标签delet…...

【项目 计网2】4.4网络模型 4.5协议 4.6网络通信的过程

文章目录 4.4网络模型OSI七层参考模型TCP/IP四层模型&#xff08;常用&#xff09;简介四层介绍 4.5协议简介常见协议UDP协议TCP协议IP协议以太网帧协议&#xff08;MAC地址封装&#xff09;ARP协议&#xff08;IP->MAC&#xff09; 4.6网络通信的过程封装分用 4.4网络模型 …...

redis入门3-在java中操作redis

Redis的java客户端 Jedis、Lettuce、Redisson、以及spring提供的spring data redis Jedis操作redis //添加依赖 <dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>2.8.0</version> </dep…...

网络安全预警分类流程

网络安全预警指南 随着信息技术的广泛应用与快速发展&#xff0c;传统业务与信息系统的融合程度不断加深&#xff0c;网络安全对国家政治、经济、文化、公共服务活动的影响进一步增大。网络安全形势日趋复杂&#xff0c;安全威胁不断变化&#xff0c;利用网络漏洞、恶意程序从…...

SpringBoot复习:(20)如何把bean手动注册到容器?

可以通过实现BeanDefinitionRegistryPostProcessor接口&#xff0c;它的父接口是BeanFactoryPostProcessor. 步骤&#xff1a; 一、自定义一个组件类&#xff1a; package com.example.demo.service;public class MusicService {public MusicService() {System.out.println(&q…...

VLT:Vision-Language Transformer用于引用的视觉语言转换和查询生成分割

摘要 在这项工作中&#xff0c;我们解决了引用分割的挑战性任务。引用分割中的查询表达式通常通过描述目标对象与其他对象的关系来表示目标对象。因此&#xff0c;为了在图像中的所有实例中找到目标实例&#xff0c;模型必须对整个图像有一个整体的理解。为了实现这一点&#…...

【开源项目--稻草】Day04

【开源项目--稻草】Day04 1. 续 VUE1.1 完善VUEAJAX完成注册功能 Spring验证框架什么是Spring验证框架使用Spring-Validation 稻草问答-学生首页显示首页制作首页的流程开发标签列表标签列表显示原理 从业务逻辑层开始编写控制层代码开发问题列表开发业务逻辑层开发页面和JS代码…...

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周&#xff0c;有很多同学在写期末Java web作业时&#xff0c;运行tomcat出现乱码问题&#xff0c;经过多次解决与研究&#xff0c;我做了如下整理&#xff1a; 原因&#xff1a; IDEA本身编码与tomcat的编码与Windows编码不同导致&#xff0c;Windows 系统控制台…...

边缘计算医疗风险自查APP开发方案

核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...

linux 错误码总结

1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...

Linux 中如何提取压缩文件 ?

Linux 是一种流行的开源操作系统&#xff0c;它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间&#xff0c;使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的&#xff0c;要在 …...

基于PHP的连锁酒店管理系统

有需要请加文章底部Q哦 可远程调试 基于PHP的连锁酒店管理系统 一 介绍 连锁酒店管理系统基于原生PHP开发&#xff0c;数据库mysql&#xff0c;前端bootstrap。系统角色分为用户和管理员。 技术栈 phpmysqlbootstrapphpstudyvscode 二 功能 用户 1 注册/登录/注销 2 个人中…...

【Linux系统】Linux环境变量:系统配置的隐形指挥官

。# Linux系列 文章目录 前言一、环境变量的概念二、常见的环境变量三、环境变量特点及其相关指令3.1 环境变量的全局性3.2、环境变量的生命周期 四、环境变量的组织方式五、C语言对环境变量的操作5.1 设置环境变量&#xff1a;setenv5.2 删除环境变量:unsetenv5.3 遍历所有环境…...

uniapp 实现腾讯云IM群文件上传下载功能

UniApp 集成腾讯云IM实现群文件上传下载功能全攻略 一、功能背景与技术选型 在团队协作场景中&#xff0c;群文件共享是核心需求之一。本文将介绍如何基于腾讯云IMCOS&#xff0c;在uniapp中实现&#xff1a; 群内文件上传/下载文件元数据管理下载进度追踪跨平台文件预览 二…...

向量几何的二元性:叉乘模长与内积投影的深层联系

在数学与物理的空间世界中&#xff0c;向量运算构成了理解几何结构的基石。叉乘&#xff08;外积&#xff09;与点积&#xff08;内积&#xff09;作为向量代数的两大支柱&#xff0c;表面上呈现出截然不同的几何意义与代数形式&#xff0c;却在深层次上揭示了向量间相互作用的…...

大数据驱动企业决策智能化的路径与实践

&#x1f4dd;个人主页&#x1f339;&#xff1a;慌ZHANG-CSDN博客 &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; 一、引言&#xff1a;数据驱动的企业竞争力重构 在这个瞬息万变的商业时代&#xff0c;“快者胜”的竞争逻辑愈发明显。企业如何在复杂环…...

shell脚本质数判断

shell脚本质数判断 shell输入一个正整数,判断是否为质数(素数&#xff09;shell求1-100内的质数shell求给定数组输出其中的质数 shell输入一个正整数,判断是否为质数(素数&#xff09; 思路&#xff1a; 1:1 2:1 2 3:1 2 3 4:1 2 3 4 5:1 2 3 4 5-------> 3:2 4:2 3 5:2 3…...