Unity笔记:C#基础(1)
杂项
虚函数
CSDN - C++虚函数详解
cnblog - C#中的虚函数virtual
常量池与new
在C#中,string是不可变的,这意味着对string对象的操作通常会返回一个新的string对象,而不会修改原始的string对象。因此,几乎所有涉及更改string内容的方法都会返回一个新的string对象。
String s = new String("xyz")
在内存中产生了多少份字符串?2个。
- “xyz” 字符串的常量池中的字符串对象
new
出来的新字符串
这种方式创建的字符串对象不会被放入常量池中,正确的操作是下面这样
string s = "xyz";
在C#中,常量池(intern pool)通常是被放置在堆中。而Substring
这类操作均不会改变原来的字符串,而是创建新的。
拆箱与装箱
拆箱(Unboxing)和装箱(Boxing)是与值类型(Value Type)和引用类型(Reference Type)之间的转换相关的两个概念。
- 装箱(Boxing):
- 装箱是指将值类型转换为引用类型的过程。在装箱中,值类型的实例被封装在一个对象中,并在堆上分配内存空间。
- 例如,将一个整数值装箱为
object
类型的实例,或者将一个结构体实例装箱为System.ValueType
类型的实例。
- 拆箱(Unboxing):
- 拆箱是指将引用类型转换为值类型的过程。在拆箱中,封装在对象中的值类型实例被提取出来,放入到一个新的值类型变量中。
- 例如,将一个装箱的整数对象拆箱为一个整数值,或者将一个装箱的结构体对象拆箱为原始的结构体实例。
装箱和拆箱操作可能会引起性能开销,因为它们涉及到数据的复制和内存分配。因此,在编写高性能的代码时应该谨慎使用。
注1:在装箱过程中,值类型的数据会被复制到堆上新分配的内存空间中,而引用会指向这个新分配的内存空间,因此装箱后的引用指向的是堆上的对象。
注2:当创建一个新的结构体时,编译器会隐式地为它添加继承自 System.ValueType 的基类,并在必要时自动实现一些与值类型相关的功能,比如装箱、拆箱等。
List
会发生拆装箱吗?会,List<object>
就会发生
List<object> objectList = new List<object>();
objectList.Add(20); // 添加一个整数(值类型)
objectList.Add("World"); // 添加一个字符串(引用类型)
可以使用is
关键字或as
关键字来检查List<object>
中的某个元素的类型。从 List<object>
中取出元素时,元素的类型会被视为 object
类型,因此任何按值类型进行的操作都需要显式手动转换类型。
C#关键字
C# 中的 sealed
关键字类似于 Java 中的 final
关键字,用于类(防止继承)或方法(防止重写)
readonly
与const
区别在于const
是编译时常量,而readonly
是运行时常量:
const
关键字用于声明常量,常量在声明时必须进行初始化,并且一旦初始化后,其值将无法更改。const变量在编译时会被直接替换为其值,因此它们的值必须在编译时就能确定。readonly
关键字用于声明只读字段,只读字段可以在声明时或构造函数中进行初始化,一旦初始化后,其值将无法更改。与const
不同,readonly
字段的值是在运行时确定的,因此可以用于在构造函数中初始化。
partial关键字
partial
关键字用于指示一个类、接口、结构体或方法是“部分定义”的。这意味着该类、接口、结构体或方法的定义可以分散在多个文件中。
// File1.cs
partial class MyClass
{public void Method1(){Console.WriteLine("Method1");}
}// File2.cs
partial class MyClass
{public void Method2(){Console.WriteLine("Method2");}
}
不要试图在不同文件中重复定义某些方法或者变量,会报错。
System.Object
在C#中,所有引用类型的基类是 System.Object
,该类实现了几个方法
Try
try
{// 可能会抛出异常的代码块
}
catch (ExceptionType1 ex)
{// 处理特定类型的异常
}
catch (ExceptionType2 ex)
{// 处理另一种类型的异常
}
finally
{// 无论是否发生异常,都会执行的代码块
}
如果catch后面没有括号里的条件,那就会捕获 try 块中抛出的任何类型的异常。自定义异常需要创建一个继承自 System.Exception 类的新类
using System;// 定义自定义异常类
public class MyCustomException : Exception
{// 可以添加自定义的构造函数和属性public MyCustomException(string message) : base(message){}
}public class Program
{public static void Main(string[] args){try{// 在适当的情况下,抛出自定义异常throw new MyCustomException("This is a custom exception.");}catch (MyCustomException ex){// 捕获并处理自定义异常Console.WriteLine("Custom Exception Caught: " + ex.Message);}catch (Exception ex){// 捕获其他类型的异常Console.WriteLine("Exception Caught: " + ex.Message);}}
}
注意在C#中,构造函数的调用顺序是由派生类向基类的方向,所以是派生类先调用基类构造函数执行,执行完才执行本类的,所以执行顺序是基类到派生类。
对于C#中的多重继承,基类构造函数的执行顺序是由派生类中基类声明的顺序决定的,一般就是这句话:
public class DerivedClass : Base1, Base2
{// ...
}
例如下题结果为6
int x = 0;
try
{ throw new Exception(); }
catch
{ x += 1; }
finally
{ x += 2; }
x += 3;
观察者模式、委托与Unity
CSDN - Unity中关于委托与事件的使用及区别
c# 事件和委托,再也不忘了
事件是函数的容器,类似C的函数指针但不太一样。声明事件时需要先声明一个委托类型
- 委托通常用于实现回调函数、事件处理等场景,它可以直接被调用。
- 事件通常用于实现发布-订阅模式,它只能在声明类的内部触发,外部无法直接调用。
一般在OnEnable()
和OnDisable()
中注册和移除事件的订阅而非Start()
,这样不会在计算机内存中留下任何无法访问的Object。事件的调用如同调用函数一般,但是在那之前需要测试事件是否为 null
,只有当任何类中没有函数订阅该事件时,该事件才会为 null
委托的本质可以看作是观察者模式的一种实现方式。委托的核心是事件,用到事件的地方就可以使用委托,例如UI交互;捡到某个物品时触发一个事件,该事件将为玩家提供升级等效果;或者触发了碰撞器能够打开门;还有就是状态管理。
实际上物体的碰撞事件通常是通过委托来实现的,如OnCollisionEnter
、OnCollisionStay
和OnCollisionExit
等方法
C#与多继承
C#不直接支持多继承,一般使用接口实现类似效果。
内存对齐
CSDN - 【C/C++】内存对齐(超详细,看这一篇就够了)
有必要注意的是,这篇的例5讲的不太对,图也错了,我把我的理解放在了下面小节“结构体嵌套的对齐”
使用 #pragma pack(n)
指令会将结构体的对齐方式设置为 n 字节的整数倍,其中n是2的次方。例如一个大小为13的变量通常会对齐到16。
使用 #pragma pack()
则取消强制对齐,恢复默认
注意:填充的缝隙也算在结构体/类的大小内,下面是个例子:
// sizeof(Base) == 8
// int4字节,bool按最大对齐
// 这里的策略是编译器在对结构体进行对齐时,按照结构体中最大的成员大小进行对齐。
class Base { int a; bool b; };
常见的对齐策略包括:
- 最严格对齐原则(Strictest Alignment):按照结构体中任何成员的要求,选择最严格的对齐方式。这意味着所有成员都按照自身的对齐要求进行对齐。
- 平均对齐原则(Average Alignment):根据结构体中所有成员的对齐要求的平均值进行对齐。这种策略可能会导致一些成员需要额外的填充来满足对齐要求。
- 特定对齐方式(Specified Alignment):有些编译器允许在结构体定义中指定对齐方式,例如使用
#pragma pack
或者__attribute__((packed))
。在这种情况下,结构体的对齐将根据指定的方式进行,而不是根据成员的大小。 - 默认对齐方式(Default Alignment):一些编译器有默认的对齐方式,可能会在不指定特定对齐方式的情况下应用。这通常会是一个合理的默认值,可以满足大多数情况下的性能和内存使用需求。
基本原则
知乎 - C/C++中内存对齐问题的一些理解
CSDN - 计算结构体大小(内存对齐原则)struct、union、class
就原则来讲,第二篇CSDN的博客是很详细的(其实很多东西我在Cppreference上没查到)
- 数据成员对齐规则,结构体(struct)(或联合(union))的数据成员,第一个数据成员存放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小或者成员的子成员(只要该成员有子成员,比如数组、结构体等)大小的整数倍开始(如:int 在 64bit 目标平台下占用 4Byte,则要从4的整数倍地址开始存储)
- 结构体的总大小,即sizeof的结果,必须是其内部最大成员长度(即前面内存对齐指令中提到的有效值)的整数倍,不足的要补齐(似乎union也需要满足这点)如果结构体A作为结构体B的成员,B的对齐大小总是按照
#pragma pack(n)
进行,其中n = max{A最大元素, B最大元素}
声明顺序的影响
struct st1 {char a[5];char b[3];int c;
};
struct st2 {char a[5];int c;char b[3];
};
// st1 == 12
// st2 == 16
这个归根到底是因为:相同类型的成员会连续存储在一起,不会因为对齐要求而产生间隔。数组内的n个成员视作相同类型的n个成员
struct st1 {int a[1];double p;char b[3];
};
struct st2 {char b[3];int a[1];double p;
};
// st1 == 24
// st2 == 16
类的对齐(虚函数与空类)
- 按照结构体对齐原则
- class含有成员变量和成员函数:计算大小的时候只与成员变量有关。与成员函数和静态成员无关,即普通成员函数、静态成员函数、静态成员变量。对类的大小没有影响。
- 虚函数对类的大小有影响,因为虚表指针的影响。在32位系统占4个字节,64位系统占8个字节。
- 多个虚函数也只算一个的影响。
在 C++ 中,对于空类(没有任何成员),其大小通常是 1 字节,这是因为 C++ 编译器会确保每个实例都有一个唯一的地址。
class Base{};
class Drived
{Base a; // 类内没东西,按4字节对齐,大小为4int b; // 一个int为4字节
};
cout << sizeof(Drived) << endl; // 输出8
可以尝试修改Base类再输出:
// 这种情况输出也是8
class Base { int a; };
// 这种情况输出是12
class Base { int a; int b; };
在C#中,类的实例化在内存中会被对齐。即使一个类没有任何成员,它也会在内存中被对齐,其大小通常是一个指针的大小,因为每个类实例在CLR(Common Language Runtime)中都会关联一个类型对象指针。
枚举的对齐
枚举类型的对齐与其底层类型一致,在C++一般是int,但是C++11可以指定为其他合法的整数类型,如unsigned int
、char
、short
,用法如下:
enum class MyEnum : underlying_type {VALUE1,VALUE2,VALUE3
};
例子如下:
enum DAY {MON = 1, TUE, WED, THU, FRI, SAT, SUN
};
// C++11新特性允许显式地指定枚举的底层类型
enum class DAY1 : char {MON = 'a', TUE, WED, THU, FRI, SAT, SUN
};
struct st1 {DAY b;
};
struct st2 {DAY1 b;
};
cout << sizeof(st1) << endl; // 4
cout << sizeof(st2) << endl; // 1
更复杂的情况,即枚举与其他的组合,就把enum
当做某种整数类型计算即可。
union的大小
联合体和结构体一样,存在内存对齐
Cppreference:联合体只大到足以保有其最大成员(亦可能添加额外的尾随填充字节)。
上面的某博客:当联合体中有数组时,一方面要保证空间能够存储这个数组的大小,另一方面要保证最终的结果是最大数据类型的整数倍。
union MyUnion {char a[10];int b;double c;
};
// 大小输出是16,而不是10
如果加上#pragma pack(1)
就是输出10了
不知道算不算参考的参考:MSDN - x64 ABI 约定概述
结构体嵌套的对齐
结合这两段代码对比:
struct stu2 {// size == 16char x;int y;char v[6];
};
struct stu1 {// size == 32char a;struct stu2 b;double f;
};
struct stu2 {// size == 24char x;int y;double z;char v[6];
};
struct stu1 {// size == 48char a;struct stu2 b;int c;int d;int f;
};
// 如果stu1去掉一个int,大小为40,去掉2个int大小也为40
换句话说,结构体嵌套的情况下,在默认对齐方式的情况下,总是n
的整数倍,其中n = max{A中最大元素, B中最大元素}
c#的sizeof
C#无法直接使用
sizeof
操作符来获取结构体的大小
在 C# 中,sizeof
操作符用于获取未托管类型或静态成员的大小,但它不能用于获取托管类型(如结构体或类)的大小。这是因为托管类型的大小在编译时并不总是已知的,而是在运行时由 CLR (Common Language Runtime) 动态确定的。
要获取托管类型(如结构体)的大小,通常可以使用 System.Runtime.InteropServices.Marshal.SizeOf
方法,该方法在运行时动态计算类型的大小。
C#结构体布局
先看上一小节内存对齐
CSDN - C#结构体内存对齐
CSDN - C#-StructLayoutAttribute(结构体布局)
在 C# 中,结构体的布局方式可以通过 StructLayoutAttribute
特性来控制,而 LayoutKind
枚举类型用于指定这种布局方式的具体类型。
- Auto:自动布局。编译器根据目标平台和类型成员的排列顺序来确定结构体的布局方式
- Sequential:顺序布局。结构体的成员按照声明的顺序依次排列,不考虑对齐和填充。
- Explicit:显式布局。需要手动指定每个成员的偏移量,可以使用 FieldOffsetAttribute 特性来指定偏移量。
[StructLayout(LayoutKind.Sequential)]
public struct Point
{public int x;public int y;
}[StructLayout(LayoutKind.Explicit)]
public struct Rect
{[FieldOffset(0)] public int left;[FieldOffset(4)] public int top;[FieldOffset(8)] public int right;[FieldOffset(12)] public int bottom;
}
Golang选手看这个
如果是Golang选手就看这篇拿Golang讲的:CSDN - 详解内存对齐
相关文章:

Unity笔记:C#基础(1)
杂项 虚函数 CSDN - C虚函数详解 cnblog - C#中的虚函数virtual 常量池与new 在C#中,string是不可变的,这意味着对string对象的操作通常会返回一个新的string对象,而不会修改原始的string对象。因此,几乎所有涉及更改string内…...
计算机科技与心理学的紧密交织:一场跨学科的深度对话
随着信息技术的飞速发展,计算机科学与心理学这两门看似迥异的学科日益呈现出密不可分的关系。本文将深入探讨计算机科学与心理学之间的相互影响和融合,揭示二者在研究方法、应用实践以及对未来社会发展的影响等方面的高度关联性。 计算机科学为心理学研究…...

【JAVA类】利用接口的多继承实现———图书管理系统【附源码】
引言 在我们学习了一些java的基础语法之后,需要把这些知识点可以串起来,这里使用一个简单的小项目可以很好的帮助我们牢记这些知识点,今天就带大家学习一个有关java的小项目,很多学校也经常把这个项目作为他们的课程设计——经典的…...

Linux进程概念僵尸进程孤儿进程
文章目录 一、什么是进程二、进程的状态三、Linux是如何做的?3.1 R状态3.2 S状态3.3 D状态3.4 T状态3.5 t状态3.6 X状态3.7 Z状态 四、僵尸进程4.1 僵尸进程危害 五、孤儿进程 一、什么是进程 对于进程理解来说,在Windows上是也可以观察到的,…...

实体店如何引流成交裂变?打造流量新引擎的秘诀
在数字化浪潮席卷的今天,实体店经营面临着前所未有的挑战与机遇。社区店作为连接居民日常生活的桥梁,如何在激烈的市场竞争中脱颖而出,实现引流、成交与裂变,成为摆在每一位实体店创业者面前的重要课题。 作为一名鲜奶吧开店5年的…...
蓝桥杯(日期问题纯暴力)
纯纯暴力,写的想吐,玛德服了。 但是复习了vector去重方法,日期的合法性判断。 #include <iostream> #include <vector> #include <cstring> #include <algorithm>using namespace std; vector<int> res; st…...
ES: ES+Kibana 环境部署
ESKibana 部署 机器信息 10.10.8.62 10.10.8.63 10.10.8.64版本选择:6.8.1 基础环境优化 所有节点 # 关闭防火墙 systemctl stop firewalld.service systemctl disable firewalld.service# 查看selinux getenforce # 关闭selinux setenforce 0 # 永久关闭se…...

Find My产品越来越得到市场认可,伦茨科技ST17H6x芯片赋能厂家
苹果发布AirTag发布以来,大家都更加注重物品的防丢,苹果的 Find My 就可以查找 iPhone、Mac、AirPods、Apple Watch,如今的Find My已经不单单可以查找苹果的设备,随着第三方设备的加入,将丰富Find My Network的版图。产…...

Linux系统——Haproxy高性能负载均衡软件
目录 一、Haproxy介绍 1.Haproxy定义 2.Haproxy主要特性 二、安装Haproxy 1.yum安装 2.第三方rpm包安装 3.编译安装 3.1解决Lua环境 3.2编译安装Haproxy 三、配置文件详解 1.状态页 2.日志管理 2.1定义日志到其他主机站点 3.指定进程线程个数 4.cpu亲缘性 5.多进…...

Python办公自动化之PDF(二)
Python操作PDF二 1、PyMuPDF简介2、 1、PyMuPDF简介 PyMuPDF(也称Fitz)开源,提供了一整套用于处理PDF文件的综合工具。使用PyMuPDF,用户可以高效地执行打开PDF、提取文本、图像和表格、操作旋转和裁剪等页面属性、创建新PDF文档以…...
登录失败重试次数安全设计方案
1、登录失败重试次数设计方案 1、无论是账号还是密码错误,统一提示:用户名或密码错误,账号剩余登录次数N! 2、同一账号连续登录失败5次,锁定该账号5分钟,5分钟后可以再重试登录。 开发设计 keyÿ…...
Django——模板
Django——模板 Django 提供一种动态生成 HTML 页面 —— 模板 1、模板语言 模板语言(DTL): 变量 , 注释 , 标签 , 过滤器 , 模板继承 1、变量 <body> <!-- 这个是前端中的注释 --> {# 这种是Django中模板语言的…...

角蜥优化算法 (Horned Lizard Optimization Algorithm ,HLOA)求解无人机路径优化
一、无人机路径规划模型介绍 无人机三维路径规划是指在三维空间中为无人机规划一条合理的飞行路径,使其能够安全、高效地完成任务。路径规划是无人机自主飞行的关键技术之一,它可以通过算法和模型来确定无人机的航迹,以避开障碍物、优化飞行时间和节省能量消耗。 二、算法介…...

Windows下 OracleXE_21 数据库的下载与安装
Oracle 数据库的下载与安装 数据库安装包下载数据库安装访问数据库进行测试Navicat连接数据库 1. 数据库安装包的下载 1.1 下载地址 Oracle Database Express Edition | Oracle 中国 1.2 点击“下载 Oracle Database XE”按钮,进去到下载页面(选择对…...

新手如何快速上手学习单片机?
读者朋友能容我,不使博文负真心 新开专栏,期待与诸君共享精彩 个人主页:17_Kevin-CSDN博客 专栏:《单片机》 学习单片机是一个有趣且有挑战性的过程。单片机是一种微控制器,广泛应用于各种电子设备和嵌入式系统中。在这…...
grpc的验证器
简介 在使用grpc库时候 ,很多时候我们需要对反序列化的参数进行校验,代码中有很多参数校验的代码,如果手动实现,会非常繁琐,对于grpc来说,在定义proto的时候使用直接定义参数的限制规则是一种更合理、更优雅的方式,插…...

无法找到concrt140.dll怎么办?concrt140.dll丢失的5种解决方法
在我们使用计算机的时候,偶尔会遭遇一些技术问题,其中一个比较常见的问题就是出现了"丢失concrt140.dll文件"的提示。当我们的电脑告诉我们缺少了concrt140.dll文件时,常常是因为某些程序无法找到这个文件而导致了程序的运行异常。…...

Elasticsearch 分享
一、Elasticsearch 基础介绍 ElasticSearch 是分布式实时搜索、实时分析、实时存储引擎,简称(ES), 成立于2012年,是一家来自荷兰的、开源的大数据搜索、分析服务提供商,为企业提供实时搜索、数据分析服务,…...
cpu masks的初始化
在内核中,有几个位图变量是用作标识cpu数量和状态的,它们分别是: 变量名称用途循环所使用的宏cpu_possible_mask系统中有多少个可以运行的cpu核for_each_possible_cpucpu_present_mask系统中有多少个可处于运行状态的cpu核for_each_present_…...

【软件测试面试】银行项目测试面试题+答案(二)
目录:导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜) 前言 面试题࿱…...

shell脚本--常见案例
1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件: 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...
IGP(Interior Gateway Protocol,内部网关协议)
IGP(Interior Gateway Protocol,内部网关协议) 是一种用于在一个自治系统(AS)内部传递路由信息的路由协议,主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...

2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面
代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口(适配服务端返回 Token) export const login async (code, avatar) > {const res await http…...

Linux --进程控制
本文从以下五个方面来初步认识进程控制: 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程,创建出来的进程就是子进程,原来的进程为父进程。…...

Kafka入门-生产者
生产者 生产者发送流程: 延迟时间为0ms时,也就意味着每当有数据就会直接发送 异步发送API 异步发送和同步发送的不同在于:异步发送不需要等待结果,同步发送必须等待结果才能进行下一步发送。 普通异步发送 首先导入所需的k…...
libfmt: 现代C++的格式化工具库介绍与酷炫功能
libfmt: 现代C的格式化工具库介绍与酷炫功能 libfmt 是一个开源的C格式化库,提供了高效、安全的文本格式化功能,是C20中引入的std::format的基础实现。它比传统的printf和iostream更安全、更灵活、性能更好。 基本介绍 主要特点 类型安全:…...

C++实现分布式网络通信框架RPC(2)——rpc发布端
有了上篇文章的项目的基本知识的了解,现在我们就开始构建项目。 目录 一、构建工程目录 二、本地服务发布成RPC服务 2.1理解RPC发布 2.2实现 三、Mprpc框架的基础类设计 3.1框架的初始化类 MprpcApplication 代码实现 3.2读取配置文件类 MprpcConfig 代码实现…...
【WebSocket】SpringBoot项目中使用WebSocket
1. 导入坐标 如果springboot父工程没有加入websocket的起步依赖,添加它的坐标的时候需要带上版本号。 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId> </dep…...

7种分类数据编码技术详解:从原理到实战
在数据分析和机器学习领域,分类数据(Categorical Data)的处理是一个基础但至关重要的环节。分类数据指的是由有限数量的离散值组成的数据类型,如性别(男/女)、颜色(红/绿/蓝)或产品类…...
python数据结构和算法(1)
数据结构和算法简介 数据结构:存储和组织数据的方式,决定了数据的存储方式和访问方式。 算法:解决问题的思维、步骤和方法。 程序 数据结构 算法 算法 算法的独立性 算法是独立存在的一种解决问题的方法和思想,对于算法而言&a…...