1. 装箱和拆箱

由于在C#中所有类型(包括值类型)都继承于System.Object类。另一方面Object类本身又是引用类型。所以值类型的数据可以隐式转换为终极基类的Object类型,同时数据由值类型变成了引用类型,即所谓的装箱。同理由于值类型也实现一些接口,当值类型数据隐式转换成相应的接口类型时,也属于装箱。而反向操作,将装箱的值类型数据显式转换回来就是拆箱。显然要有装箱操作,才有拆箱操作。如果尝试对null引用拆箱或拆箱时数据类型不对的话,会报错。

 int i = 123;object o = i;//装箱int j = (int)o;//拆箱float k = (float)o;//也是拆箱


相对于简单的赋值而言,装箱和拆箱过程需要进行大量的计算,应尽量避免。

2. 集合(动态数组)

由于数组要在一开始指定数组的大小,不能添加多于数组大小的数据。于是C#提供了可以的动态改变存取数组大小的集合类。常用的有:arrayList,List,HashTable,Dictionary<Tkey,TValue>,Stack和Queue。
1. ArrayList & List
ArrayList和List的用法基本一致,差别仅是ArrayList里存的是object类数据,所以实际可以存任何数据(存值类型数据时自动装箱),List是泛型类,需要在声明时指定存储的类型。由于ArrayList可能有装箱和拆箱的操作,相对耗性能,而且有可能拆箱是转换失败而报异常(不是类型安全)。官方推荐尽量不使用ArrayList,即使要存不同类型的对象,也推荐使用List。

  1. 常用属性:
    Count :ArrayList中包含元素的个数。
    Capacity :ArrayList现阶段可容元素的大小。
    Capacity一开始默认为4。在元素个数满的时候自动翻倍(x2)。
    也可以通过构造函数指定一开始的大小。同样在元素个数满的时候也会自动翻倍。也可以直接修改Capacity,但不能小于Count。不然会报错。
    列表名[index]:可以通过索引提取和修改数据。

  2. 常用方法:
    Add(data):添加数据到末尾
    Insert(Index,data):添加数据到索引Index。
    Clear():清空列表(不会缩小容器大小)
    Remove(data):清除第一个匹配的数据
    RemoveAt(index):删除索引位置的数据
    Reverse():倒序元素
    IndexOf(data):返回第一个匹配的元素的索引。

2. Hashtable/Dictonary<Tkey,TValue>
和ArrayList和List差不多,Dictonary是Hashtable的泛型版本。同样不推荐使用Hashtable。以Hashtable为例,每个元素存在一个键/值对。作为键的对象必须是唯一不可变的,且不能为null。值可以重复。

  1. 常用属性:
    Count:获取键值对个数。
    集合名[index]:可以通过索引提取和修改数据。

  2. 常用方法:
    Add(键,值):添加带有指定键和值的元素,键已存在时会报错
    Clear():清空所有元素。
    Remove(键):移除相应的键值对元素。
    ContainsKey(键):确认是否包含该键。
    ContainsValue(值):确认是否包含该值。

3. Stack和Queue
Stack和Queue都有非泛型和泛型版本(Stack和Queue),同样推荐使用泛型版本。
栈Stack是先进后出的数据结构,就像一堆堆叠的椅子。每次只能取出最后叠上的椅子。想要取出最早放入的椅子,只能把它之后放入的椅子都取出来。汉诺塔就是三个栈结构。
常用方法:
Push(data):往栈顶放数据。
Pop():返回并删除顶部数据。
Peek():返回但不删除顶部数据。

队列Queue是先进先出的数据结构,就如排队,先获取的是先放入的元素。
常用方法:
Enqueue(data):往队尾加数据。
Dequeue():返回并删除队首的数据。
Peek():返回但不删除队首的数据。

3. 异常处理

程序错误类型:
1) 语法错误:在编译期间就报错。
2) 异常:在程序运行时出错非正常中止。
3) 逻辑错误:程序正常运行,但结果和预期不一样。

C#中也将各种异常封装为类,其基类为Exception类。在程序遇到问题时,就抛出(throw)相应的异常实例。之后程序自动中止。
C#提供了try-catch-finally语法来捕获异常,进行相应处理,同时让程序不中止。

try
{//可能异常的代码
}
catch(Exception e)//捕获异常
{//捕获到异常时运行的代码
}
finally//可选
{//无论是否捕获到异常都会运行的代码
}

在catch()括号中可以写具体的异常类,写Exception即捕获所有异常。后面的e变量为捕获到异常的对象。可以通过变量输出异常的信息和位置。

catch(Exception e)
{Debug.Log(e.Message);//输出异常的信息Debug.Log(e.StackTrace);//输出异常的位置
}

不想操作异常变量时可以直接写异常类型

catch(Exception)
{…}

如果可能发生多种异常,想对不同异常进行不同处理,可以写复数个catch的语句。

catch(Exception1)
{…}
catch(Exception2)
{…}
catch(Exception)
{…}

由于catch语句是从上往下顺序比对执行。比对到一个就执行该catch语句,而不会再执行其他语句。所以Exception父类的语句要放最后(如果有的话)。
注意:一旦try里的语句发生异常后,异常语句之后的语句就都不会执行了。

我们也能自己定义异常,只要继承Exception基类就好了。

class EqualZeroException: Exception//等于零异常
{public EqualZeroException(){base.Message = “不能为零”;}
}
使用异常:
if(num == 0)
{throw new EqualZeroException();//用throw关键字抛出新建的异常对象。
}

4. 委托和事件

委托是一种引用类型,表示对具有特定参数列表和返回类型的方法的引用,使用委托能够将方法本身作为参数进行传递。
1. 委托的定义:给委托变量命名,同时规定可以引用哪些类型的方法。

delegate void Function(int x);//可引用的方法类型为1个int类型参数,无返回值。

要引用的方法和委托必须具有相同的形参列表和返回类型。
2. 声明一个委托变量

Function func1;

3. 将方法封装到委托变量里

func1 = new Function(Func);//如果方法是当前类的方法,使用方法名引用
func1 = new Function(Test.Func);// 如果方法是外部类的静态方法,使用类+方法名引用
Test t = new Test();
func1 = new Function(t.Func);// 如果方法是外部类的非静态方法,实例名+方法名引用
func1 = t.Func;//可以将前面的构造函数省略,直接写相应的方法名引用。

4. 委托的调用

func1();//就像普通方法一样使用,如果有返回值,也需要一个变量接收。

5. 多播委托
一个委托变量可以用+,+=封装多个委托,在执行时按封装顺序依次执行。

func1+=Func1;//增加一个委托
func1+=Func2;//增加一个委托
func1();//依次调用Func1,Func2

也可以用-,-=删除已经封装的委托

func1-=Func1;//删除之前加的Func1方法
func1-=Func2;// 删除之前加的Func2方法
func1-=Func3;//如果本身就没引用,使用删除也没有效果
func1();//注意执行没有引用方法的委托会报空引用异常,使用前应检查是否为空。

6. 委托的简化

  1. 通用委托:
    对于一些常用的委托系统直接定义了,避免了手动定义,可以直接声明变量。
    例如:
Action<int> func1;//用Action关键字声明了一个int形参无返回值的委托。
Func<int, string> func2;//用Func 关键字声明了一个int形参,string类型的返回值的委托。

Func委托中<>内必须有一个类型作为返回值的类型。有多个类型时,最后一个类型作为返回值的类型。

  1. 匿名方法和Lambda表达式
    对于想委托一些临时的方法,又不想专门声明一个方法时,可以用匿名方法和Lambda表达式。
  2. 匿名方法
Action act;act = delegate(){…};//一个无参无返回值的匿名方法。Func<int> fun;
fun = delegate(){…return …}一个无参有返回值的匿名方法。返回值类型按委托定义。
  1. Lambda表达式
想省略delegate,之前的可改为:
act = ()=>{…};
fun = ()=>{…return…};

其他:

注意:由于匿名方法和Lambda表达式无方法名,不能被指定地取消引用。

act += ()=>{Debug.Log(‘a’);};
act -= ()=>{Debug.Log(‘a’);};//之前的方法并不会被取消。

3. 发布和订阅模式
实际上就是在一个类(发布者)中声明一个公共委托。其它的类(订阅者)通过向这个委托添加自己的方法的引用(注册/订阅)来实现发布者在某一时刻统一调用相关的订阅者的方法。而订阅者不必知道为什么触发,只会收到要执行之前注册的方法的信息。实现了解耦合。

例如:

class Program{static void Main(string[] args){Pulisher p1 = new Pulisher("电台1");Pulisher p2 = new Pulisher("电台2");Listener l1 = new Listener("A");Listener l2 = new Listener("B");l1.Subscrib(p1);//A订阅了电台1l2.Subscrib(p1);//B订阅了电台1l1.Subscrib(p2);//A订阅了电台2p1.BoardCast("节目1");//电台1发布了节目1p2.BoardCast("节目2");//电台2发布了节目2}}class Pulisher//发布者{public Action<string> act;//发布了一个委托public string Name { get; set; }public Pulisher(string name){Name = name;}public void BoardCast(string message)//广播{message = Name +":"+ message;act(message);//执行委托(发布一条消息)}}class Listener//订阅者{public string Name { get; set; }public Listener(string name){Name = name;}public void Subscrib(Pulisher pulisher )//订阅操作{pulisher.act += Listen;//往发布者里订阅}public void Listen(string str)//要订阅到委托的方法{Console.WriteLine($"{Name}在听{str}");}}

输出为:
A在听电台1:节目1
B在听电台1:节目1
A在听电台2:节目2

4. 事件(Event)
但是以上实现有一个缺陷,就是电台容易被劫持。因为委托是公共的,可以直接从Pulisher对象点出来调用。也就是可以不通过电台来发布消息。还有只要一个Listener将订阅操作的+=改为=,就能覆盖掉之前所有的订阅。为了防止这种事,C#提供了event关键字对委托进行封装。

public event Action<string> act;
一旦加了event,这个委托就变成了事件。
事件的特点是:

1) 事件的赋值和执行只能在声明事件的同一个类中。
2) 在类外,事件只能用于+=或-=的左边。

5. IO流

数据在内存里,当程序结束之后,内存里相关数据就会被清空,同时为了程序能实时的处理一些文件,就需要在程序中进行IO操作(Input/Output)。
有关IO的操作,在C#中也都被封装成类,在System.IO命名空间里。
常用的类有:
1. Path类
静态类,用于路径和字符串的处理。
Combine方法:将多个字符串加入/或\拼成一个路径的字符串。
GetFileName方法:获取全路径字符串中的文件名,包含后缀。
GetExtension方法:只获取后缀。
其他方法参看:
https://docs.microsoft.com/zh-cn/dotnet/api/system.io.path?view=netcore-3.1

2. Directory类
静态类,处理文件目录
CreateDirectory方法:创建目录
Delete 方法:删除目录
Exists 方法:判断目录是否存在。
其他方法参看:
https://docs.microsoft.com/zh-cn/dotnet/api/system.io.directory?view=netcore-3.1

3. DirectoryInfo类
声明的每个实例代表一个目录。可以对这个目录进行相应操作。

4. File类
静态类,用来处理文件。
Create 方法:创建文件
Delete 方法:删除文件
Exists 方法:判断是否存在该文件
其他方法参看:
https://docs.microsoft.com/zh-cn/dotnet/api/system.io.file?view=netcore-3.1

5. FileInfo类
声明的每个实例代表一个文件。可以对这个文件进行相应操作。

6. 流:
流是指通过通信路径传递的字节序列。在C#中依旧将其封装为类。其中Stream类是所有流的抽象基类。主要有两个操作:
对流进行读取——将流中的数据读取到具体的数据结构(如文件)
对流进行写入——把数据结构中的数据写入到流中。(如从文件中读取)

流主要有4个派生类:
NetworkStream——提供网络通信的基础数据流;
FileStream——用于将数据已流的形式写入文件,或从文件中读取;
MemoryStream——用于对内存中的数据进行写入或读取;
GZipStream——提供用于压缩和解压缩流的数据。
按传输单位分类:
字节流:以字节为单位进行读写
能处理任何类型数据

 字符流:以字符为单位进行读写只能处理字符数据

按读写器分类:
文本读写器:TextReader TextWriter//是字符串读写器和流读写器的抽象基类
字符串读写器:StringReader StringWriter
二进制读写器:BinaryReader BinaryWriter
流读写器:StreamReader StreamWriter

StreamWriter类
构造器:
StreamWriter(Stream);在一个字节流上建立流写出器,用于写字符。
StreamWriter(string);在文件上建立流写出器,用于写字符
StreamWriter(Stream,Encoding);可指定字符集

方法:
Write : 具有多个重载,都以字符形式写数据。
WriteLine:具有多个重载,都以字符形式写数据,结尾有换行。
AutoFlush:可设置或查询是否自动刷缓存。
Flush:强制刷缓存。
Close:关闭流写出器。

StreamReader类
构造器:
StreamReader(Stream):在一个字节流上建立流读取器,用于读取字符。
StreamReader(string):在文件上建立流读取器,用于读取字符。
StreamReader(Stream,Encoding):可指定字符集
StreamReader(string,Encoding):可指定字符集。

方法:
Read:读一个字符并返回,如到达底部返回-1
ReadBlock:读若干字符存入字符数组,返回实际读到的字节数,如到达底部返回0。
ReadLine:读一行并返回一个字符串,如到达底部返回null。
ReadToEnd:读全部文本,返回一字符串。
Close:关闭流读取器
注意:ReadLine读到空行时,也会返回一个空字符串。

读写文件除了通过FileStream类,还可以通过File类的静态方法ReadAllText()和WriteAllText()(实际上这两个方法内部也是调用了FileStream类的方法)。
由于File类的读写有大小限制,只能读小的文件(100M一下)。

大文件——>选择FileStream类读写。
http://www.manongjc.com/article/115367.html
小文件——>非文本文件——>File类的ReadAllBytes/WriteAllBytes
——>文本文件——>单行读写:StreamReader/StreamWriter类
——>整个读写:File类的ReadAllText/WriteAllText

Unity超基础学习笔记(四)相关推荐

  1. Unity超基础学习笔记(二)

    Unity超基础学习笔记(二) 1. 基本数据类型的扩展 之前在K12中学习了一些基本的数据类型,实际上C#支持更多的数据类型.如下: 注意无符号整型数和有符号整型数的表示范围,例如: int 能表示 ...

  2. Unity超基础学习笔记(三)

    1. 面向对象的编程 早先面向过程编程的问题: 1) 功能和数据分离,使用的建模概念不能直接映射到问题域中的对象,不符合人们对现实世界的认识和思维方式. 2) 自顶向下的设计方法限制了软件模块的可复用 ...

  3. Unity超基础学习笔记(一)

    1.安装Unity和认识Unity界面 通过访问unity下载来下载unityHub或者直接下载unity.(应该需要注册个unityID).本次课程用的版本是2019.4.3f1. 打开后新建一个项 ...

  4. 【台大郭彦甫】Matlab入门教程超详细学习笔记四:数据类型与文件读写(附PPT链接)

    变量类型与文件读写 前言 一.变量类型 1.numeric(数值类型) 2.char(字符类型) 3.string(字符串类型) 4.structure(结构体) 5.cell(元胞数组) 5.高维数 ...

  5. 陈宝林《最优化理论与算法》超详细学习笔记 (四)————第四章 对偶理论

    陈宝林<最优化理论与算法>超详细学习笔记 (四)----第四章 对偶理论 1. 对偶问题的提出 2. 线性规划的对偶理论 2.1 原问题与对偶问题的关系 2.2 对偶问题的基本性质 3. ...

  6. 【Java基础学习笔记】- Day11 - 第四章 引用类型用法总结

    Java基础学习笔记 - Day11 - 第四章 引用类型用法总结 Java基础学习笔记 - Day11 - 第四章 引用类型用法总结 4.1 class作为成员变量 4.2 interface作为成 ...

  7. UE5 Shader基础学习笔记——13-20 DetailNormal/Smoothstep/Length/CeilFloorRound/DDXDDY/SinCos/Power

    UE5 Shader基础学习笔记--13-20 DetailNormal/Smoothstep/Length/CeilFloorRound/DDXDDY/SinCos/Power Lec13 Deta ...

  8. Task 06 数据增强;模型微调;目标检测基础 学习笔记

    Task 06 数据增强:模型微调:目标检测基础 学习笔记 数据增强 图像增广 在5.6节(深度卷积神经网络)里我们提到过,大规模数据集是成功应用深度神经网络的前提.图像增广(image augmen ...

  9. UE5 Shader基础学习笔记——01-12 图形管线/创建shader/数学节点/贴图压缩/LerpDotUV/常用向量/坐标空间/MinMaxClampSaturate/法线贴图混合

    UE5 Shader基础学习笔记--01-12 图形管线/创建shader/数学节点/贴图压缩/LerpDotUV/常用向量/坐标空间/MinMaxClampSaturate/法线贴图混合 Lec01 ...

最新文章

  1. 压缩版styleGAN
  2. mysql8.0 本地监听端口_mysql8.0启动后不能正常监听端口的问题处理
  3. 腾讯极客挑战赛邀你“码上种树”
  4. 前端学习(2672):ts初步概念和功能实现
  5. NLP《词汇表示方法(七)BERT》
  6. String,StringBuilder, StringBuffer
  7. 聚类算法_案例实战:聚类实战
  8. python的socket编程接收浏览器上传的文件_使用python套接字编程将文件发送到浏览器...
  9. 抢占朋友圈C位 闪耀世界杯 就要Pick 腾讯云CDN
  10. 淘宝店铺链接获取seller id,拿到店铺所有商品接口,接口接入技术解决方案
  11. java hl7v3_HL7标准V3开发框架中个模型的关系
  12. RC522(RFID模块)实践总结
  13. php流量统计代码_用php编写的简单的网站流量统计程序
  14. 一、OpenAI ChatGPT 注册使用
  15. Unity 自定义自发光材质 shader (对比Standard Eimission)
  16. java web工程web.xml配置详解
  17. 【我的渲染技术进阶之旅】Google开源的基于物理的实时渲染引擎Filament源码分析:在android中如何使用cmgen命令自动将.hdr文件转换为.ktx文件或者.rgb32文件等?
  18. 【图像分割】基于计算机视觉实现胸部CT肺质提取附matlab代码
  19. 正数/负数的原码、反码、补码
  20. Docker 三大核心之容器 之一 docker ps

热门文章

  1. vue重复路由_解决vue路由name同名,路由重复的问题
  2. 不让html缓存图片吗,html – 如何强制Web浏览器不缓存图像
  3. linux+下c语言编程项目,精通UNIX下C语言编程与项目实践
  4. mongodb objetcid_mongodb(1)
  5. 国内人气设计师交流平台集设
  6. PNG免抠古风纹理背景太漂亮了,直接应用的才是好素材
  7. 高品质UI设计模板PSD下载,设计师的最佳临摹素材
  8. mysql关联语句优化_MySql语句关联优化问题,为什么加了限制条件反而更慢?
  9. php 去除小数点后,php-删除两位小数点后的数字,而不舍入该值
  10. Python-Socket编程学习(11.3)