初始化obs/Unity仓库
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
|
||||
| 类型 | 符号 | 占用空间 |
|
||||
| ----- | ------- | ----- |
|
||||
| 有符号整形 | sbyte | 1个字节 |
|
||||
| | int | 4个字节 |
|
||||
| | short | 2个字节 |
|
||||
| | long | 8个字节 |
|
||||
| 无符号整形 | byte | 1个字节 |
|
||||
| | uint | 4个字节 |
|
||||
| | ushort | 2个字节 |
|
||||
| | ulong | 8个字节 |
|
||||
| 浮点数 | float | 4个字节 |
|
||||
| | double | 8个字节 |
|
||||
| | decimal | 16个字节 |
|
||||
| 字符 | char | 2个字节 |
|
||||
| 布尔 | bool | 1个字节 |
|
||||
@@ -0,0 +1,220 @@
|
||||
#### 一.转义字符
|
||||
#### 常用的转义字符有:
|
||||
1.斜杠单引号,表示单引号
|
||||
例子 string str="\\'哈哈哈\\' "
|
||||
2.斜杠双引号,表示双引号
|
||||
例子 string str="\\\\'哈哈哈\\\\' "
|
||||
3.斜杠+n表示换行
|
||||
4.双斜杠表示单斜杠
|
||||
#### 不常用转义字符:
|
||||
1.制表符t 相当于按下tab,空4格
|
||||
2.光标退格字符 b,是光标位置向后推一个
|
||||
3.空字符0 无实际效果
|
||||
4.警报音 a 系统发出提示音
|
||||
|
||||
#### 取消转义字符
|
||||
在字符串前面加上@,将所有转义字符按照字面显示
|
||||
|
||||
### 二:类型转换
|
||||
#### 隐式类型转换
|
||||
小转大,不会影响精度,可以自动转换
|
||||
#### 显示类型转换
|
||||
##### 1. 括号强转
|
||||
##### 2.Parse法
|
||||
将string转成目标类型
|
||||
##### 3.Convert法
|
||||
##### 4.其他类型转string ToString()方法
|
||||
|
||||
### 三:枚举
|
||||
枚举是一组命名的整型常量
|
||||
它的本质是整数类型的包装,枚举在编译后会被编译为一个**密封类(sealed class)**,继承自 `System.Enum`(而 `System.Enum` 又继承自 `System.ValueType`),因此枚举是值类型。
|
||||
每个枚举成员本质上是一个**常量整数**,默认从 `0` 开始递增(也可手动指定值)。例如:
|
||||
```
|
||||
public enum Time { yi, er, san }
|
||||
```
|
||||
编译后等价于
|
||||
```
|
||||
public sealed class Time : Enum
|
||||
{
|
||||
public const int yi = 0;
|
||||
public const int er = 1;
|
||||
public const int san = 2;
|
||||
}
|
||||
```
|
||||
### 四:接口
|
||||
常规的接口声明是这样的
|
||||
```
|
||||
interface ICanRun
|
||||
{
|
||||
void Run();
|
||||
}
|
||||
```
|
||||
我们不需要显式的去写访问修饰符,接口默认的是internal,程序集可见
|
||||
内部的成员都是public的,继承了接口的方法也是public.
|
||||
继承了接口的类,他需要实现接口提供的契约方法
|
||||
|
||||
```
|
||||
public class Dog : ICanRun
|
||||
{
|
||||
public void Run()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
```
|
||||
以上是我们接口中的常规写法,但是会有一些问题出现.
|
||||
假如有两个接口,他们内部都有一个Run方法
|
||||
```
|
||||
interface ICanFastRun
|
||||
{
|
||||
void Run();
|
||||
}
|
||||
interface ICanSlowRun
|
||||
{
|
||||
void Run();
|
||||
}
|
||||
```
|
||||
那么我们的Dog继承了两个接口,这时候在使用常规的方法去实现接口方法,就会出现一些问题.
|
||||
我们需要新的方法去解决问题.
|
||||
==显式接口实现==
|
||||
我们的Dog在同时继承了两个接口的时候,实现方法应该用显示接口实现
|
||||
```
|
||||
public class Dog:ICanFastRun, ICanSlowRun
|
||||
{
|
||||
void ICanSlowRun.Run()
|
||||
{
|
||||
Console.WriteLine("我可以跑的很慢");
|
||||
}
|
||||
void ICanFastRun.Run()
|
||||
{
|
||||
Console.WriteLine("我可以跑的很快");
|
||||
}
|
||||
}
|
||||
```
|
||||
显示接口实现是非常清晰易懂的,让我们知道这个是那个接口的那个方法,但是他会有一些问题,
|
||||
==我们不能直接在Dog变量里面调用Run方法,需要将Dog强转为接口类型==
|
||||
```
|
||||
class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
Dog dog = new Dog();
|
||||
dog.Run(); //会报错
|
||||
}
|
||||
}
|
||||
```
|
||||
这就是麻烦的地方,我们需要对Dog进行类型转换才可以调用对应的Run方法
|
||||
```
|
||||
class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
Dog dog = new Dog();
|
||||
((ICanFastRun)dog).Run(); //将dog转换为ICanFastRun类型,可移植性跑得快的Run方法
|
||||
((ICanSlowRun)dog).Run(); //将dog转换为ICanSlowRun类型,可移植性跑得慢的Run方法
|
||||
}
|
||||
}
|
||||
```
|
||||
显示接口实现,从另一层面来讲,也是对方法的一种隐藏,对API的一种清洁.
|
||||
### 五:多态中的类型
|
||||
```
|
||||
public class Animal
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public class Dog : Animal
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public class Cat : Animal
|
||||
{
|
||||
|
||||
}
|
||||
class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
Animal animal = new Animal();
|
||||
Animal dog = new Dog();
|
||||
Animal cat = new Cat();
|
||||
}
|
||||
}
|
||||
```
|
||||
在上述代码当中请问animal,dog,cat他们三个都是什么类型?
|
||||
答案是两个,他们即是Animal又是Dog(Cat),他们两者兼备
|
||||
这是需要区分情况的
|
||||
##### ==在编译时==
|
||||
他们三者都是Animal类型的
|
||||
##### ==在运行时==
|
||||
他们是new 后面的类型
|
||||
dog是Dog类型
|
||||
cat是Cat类型
|
||||
|
||||
|
||||
|
||||
|
||||
### 六:多态中的new关键字
|
||||
new关键字在类当中用来隐藏基类的方法
|
||||
在继承链当中,他会影响运行时多态
|
||||
```
|
||||
public class Animal
|
||||
{
|
||||
public virtual void Eat()
|
||||
{ Console.WriteLine("我正在吃");
|
||||
}
|
||||
}
|
||||
|
||||
public class Dog : Animal
|
||||
{
|
||||
public new void Eat()
|
||||
{
|
||||
Console.WriteLine("狗正在吃");
|
||||
}
|
||||
}
|
||||
class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
Animal animal = new Animal();
|
||||
Animal dog1 = new Dog();
|
||||
Dog dog2 = new Dog();
|
||||
animal.Eat();
|
||||
dog1.Eat();
|
||||
dog2.Eat();
|
||||
}
|
||||
}
|
||||
```
|
||||
上面代码的输出结果是
|
||||
```
|
||||
我正在吃
|
||||
我正在吃
|
||||
狗正在吃
|
||||
```
|
||||
关键点在于Animal dog1 = new Dog();
|
||||
dog1究竟输出的是什么呢?
|
||||
答案是"我正在吃"
|
||||
我们要研究为什么他会这样输出
|
||||
```
|
||||
1. 编译阶段:编译器只认 “声明类型”,确定要调用的方法
|
||||
|
||||
dog1的声明类型是Animal(=左边),编译器在编译时会做两件事:
|
||||
|
||||
- 检查Animal类中是否有Eat()方法:发现Animal有public virtual void Eat()(虚拟方法),符合调用条件,编译通过;
|
||||
|
||||
- 记录 “要调用的是Animal类的Eat()方法”:因为Dog类的Eat()用new修饰,编译器会将其视为 “子类新增的独立方法”,而非对Animal.Eat()的重写,所以不会将dog1与Dog.Eat()关联。
|
||||
|
||||
简单说:编译时,编译器认为dog1是Animal类型,只能调用Animal的方法,根本 “看不到”Dog类用new隐藏的Eat()。
|
||||
|
||||
2. 运行阶段:CLR 执行 “编译时确定的方法”
|
||||
|
||||
运行时,dog1的实际类型是Dog(=右边new Dog()),但 CLR 的执行逻辑受new关键字影响:
|
||||
|
||||
- 若子类用override重写:CLR 会优先执行 “实际类型(Dog)的重写方法”(多态生效);
|
||||
|
||||
- 若子类用new隐藏:CLR 会执行 “编译时确定的父类方法(Animal.Eat())”,因为new修饰的方法与父类方法无关联,CLR 不会去子类中找这个 “独立方法”。
|
||||
|
||||
所以,运行时dog1.Eat()最终执行的是Animal类的Eat(),输出 “我正在吃”。
|
||||
```
|
||||
简单的说,new隐藏了方法之后,他在编译时是什么类型,就执行谁的方法.
|
||||
@@ -0,0 +1,11 @@
|
||||
![[deepseek_mermaid_20260204_d63c65.png]]
|
||||
.net平台从最开始是使用的.net framework,它可以跨语言但是不能跨平台,后面第三方提出了mono的解决方案,可以给.net framework用来跨平台,但这是第三方的解决方案。后面微软自己推出了.net core,作为官方的,开源的,跨平台的解决方案。后面在2020年,提出了统一的.net 5,她统一了所有的平台,包括.net frame和.net core。这是.net的生态发展史。
|
||||
下面我们讲讲mono和IL2CPP两种跨平台的方式。
|
||||
mono的工作流程是
|
||||
mono:C#代码->IL代码->CLR运行时JIT计时编译为机器码从而运行。
|
||||
IL2CPP:C#代码->IL代码->C++代码->本地编译C++代码为机器码->运行。
|
||||
区别就在于对于IL代码的处理,IL2CPP是AOT提前编译,提前就处理好代码,最终打包出去的,只有原生机器码,没有任何其他代码。
|
||||
mono的话,打包出去的还存储这IL代码,在运行时会有一个虚拟机去编译IL代码为机器码去运行。
|
||||
还有一个问题:Unity怎么知道我们的游戏需要打包到那个平台,从而调用该平台的C++编译器来编译c++代码让我们可以使用呢?
|
||||
Unity本身并不提供所有的C++编译器,而是我们在打包不同平台的时候,比如Android需要安装NDK,打包windows需要安装vs等等,在这里我们就可以使用这些工具的C++编译器来帮助我们进行编译。所以开发的时候要提前在build里面选好平台
|
||||
|
||||
Reference in New Issue
Block a user