一,入门知识
1. 输入输出
//输出空行
Console.WriteLine("hello world!");
//输出不空行
Console.Write("hello world!");
//读入一行
Console.ReadLine();
//一键输入
Console.ReadKey();
2.变量
- 有符号变量:
sbyte:-128~127,int:-21亿~21亿多,short:-32768~32767 ,long:-9百万兆~9百万兆
- 无符号整形变量:
byte: 0~255, uint:0~24亿多, ushort:0~65535,ulong: 0~18百万兆
- 浮点数
float:7~8位有效数字(0之后的有效数字),会四舍五入
在最后加上f(在C#中小数默认为double类型,只有加了f才能算为float类型)
float f = 0.01234567890f;
double :储存15~17位有效数字
decimal : 存储27~28位有效数字,后面要加m,会四舍五入
- 特殊类型
bool true false表示真假,char 单个字符(加上‘ ’),string 字符串(加上“ ”)
3.常量(必须有初始值)(不可被改变)
const 类型 名字 = 初始值;
4.折叠代码
#region 名字
代码内容
#endregion
5.转义字符 \+符号,取消转义字符:在前面+@
6.类型转换
-
隐式转换:大范围 转 小范围
相同大类型之间的转换 : long->int->short->sbyte;ulong->uint->ushort->byte;double -> float(decimal不可以用隐式转换变成double,但是可以隐式转换整型);特殊类型(bool,char,string之间不存在隐式转换)
不相同大类型之间的转换 : 无符号的数 不能隐式转换装 有符号的数 ; 有符号的数 装 范围比它小的无符号数;浮点数 装 任何类型的整数;整数 不能隐式转换装 浮点数;char类型 隐式转换成整型和浮点型(ASCII码)
总结:隐式转换规则
高精度-> 低精度
double->float->整型(有符号,无符号)->char
decimal->整型(有符号,无符号)->char
string和bool不参与隐式转换规则
-
显示转换
括号转换,但是要注意范围问题和精度问题。
parse转换:变量类型.parse(字符串); 要注意只有字符串可以转换为该类型的才可以用parse。
convert法: convert.To目标类型(变量或常量),会四舍五入,
其他类型转string: 变量.toString();
7.异常捕获
作用:避免当代码报错时,出现程序卡死的情况
写法:
//必备部分
try
{
//可能出现异常的代码块放入其中
}
catch
{
//出现问题后执行catch中的代码
//catch(Exception e)可以带着try中的错误原因进入catch,可以打印
}
//可选部分
finally
{
//无论出现异常与否,都会执行
}
8.算数运算符(太简单了不写)
9.字符串拼接
用+拼接: str1+str2;
用固定语法拼接:
string str = string.Format("我是{0},我今年{1}岁,我想要{2}",mood,18,"天天学习,好好向上");
Console.Writeline(str);
在写待拼接内容里占位符{数字},数字由0·9
控制台打印:
Console.WriteLine("A{0}B{1}c{2}",1,true,false);
Console.Write("A{0}B{1}c{2}",1,true,false);
注意:后面不能比占位符少,否则会报错
二,基本知识
1.复杂数据类型
A.枚举
1.枚举是一个被命名的整型常量的集合,一般被用来表示状态,类型等
2.申明枚举:创建一个自定义的枚举类型
申明枚举变量:使用申明的自定义枚举类型,创建一个枚举变量
3.申明枚举语法:
enum E_自定义名称
{
自定义枚举项名字0,
自定义枚举项名字1,
自定义枚举项名字2,
自定义枚举项名字3,
//第一个默认值为0,其他依次累加
//如果给其中某一个赋值,剩下的也还是会依次累加
}
4.枚举申明地方:namespace语句块中,struct中,不能在函数语句块中申明
5.枚举的使用:(配合条件语句,if else,和switch)
自定义枚举类型 自定义名称 = 默认值(自定义枚举类型.枚举项);
E_monsterType monster1 = E_monsterType.Boss;
if(monster1 == E_monsterType.Boss)
{
Console.WriteLine("Boss");
}
else
{
Console.WriteLine("normal");
}
E_palerType player1 = E_palerType.Main;
switch (palyer1)
{
case:E_plaerType.Main;
break;
case:E_plaerType.Other;
break;
default:
break;
}
6.枚举的类型转换
枚举和int转换: int i = (int)playerType;
枚举和string转换:string str = playerType.ToString
(就是转换为枚举项的名字,比如main或者other)
string和枚举的转换:
playerType = (E_playerType)Enum.Parse(typeof(E_playerType),“other”);
(playerType = other)
枚举例题
namespace Study
{
enum E_qqType
{
Online,
Busy,
Leave,
Individual,
}
enum E_coofeType
{
M,
B,
S,
}
enum E_gamePerson
{
man,
woman,
zhanshi,
lieren,
fashi,
}
internal class Program
{
static void Main(string[] args)
{
#region QQ状态
try
{
Console.WriteLine("请输入QQ状态:(0在线,1忙碌,2离开,3隐身)");
int type = int.Parse(Console.ReadLine());
E_qqType qqType = (E_qqType)type;
Console.WriteLine(qqType);
Console.WriteLine();
}
catch
{
Console.WriteLine("请输入数字");
}
#endregion
#region 星巴克咖啡
try
{
Console.WriteLine("请输入你想要的size(0中杯,1大杯,2超大杯)");
int type = int.Parse(Console.ReadLine());
E_coofeType cafe = (E_coofeType)type;
switch (cafe)
{
case E_coofeType.M:
Console.WriteLine("你购买了中杯咖啡,消费35元");
Console.WriteLine();
break;
case E_coofeType.B:
Console.WriteLine("你购买了大杯咖啡,消费40元");
Console.WriteLine();
break;
case E_coofeType.S:
Console.WriteLine("你购买了超大杯咖啡,消费43元");
Console.WriteLine();
break;
}
}
catch
{
Console.WriteLine("请输入数字:");
}
#endregion
#region 游戏人物
try
{
string sexString = " ";
string jueseString = " ";
string zhiyeString = "";
int gongji = 0;
int fangyu = 0;
Console.WriteLine("请输入你想选择的性别(0男,1女)");
int sexy = int.Parse(Console.ReadLine());
Console.WriteLine("请输入你想选择的角色(2战士,3猎人,4法师)");
int juese = int.Parse(Console.ReadLine());
E_gamePerson p = (E_gamePerson)sexy;
switch(p){
case E_gamePerson.man:
sexString = "男性";
gongji += 50;
fangyu += 100;
break;
case E_gamePerson.woman:
sexString = "女性";
gongji += 150;
fangyu += 20;
break;
}
E_gamePerson q = (E_gamePerson)juese;
switch (q)
{
case E_gamePerson.zhanshi:
gongji += 20;
fangyu += 100;
jueseString = "战士";
zhiyeString = "冲锋";
break;
case E_gamePerson.lieren:
gongji += 120;
fangyu += 30;
jueseString = "猎人";
zhiyeString = "假死";
break;
case E_gamePerson.fashi:
gongji += 200;
fangyu += 10;
jueseString = "法师";
zhiyeString = "奥术冲击";
break;
}
Console.WriteLine("你选择的角色是\"" + sexString +jueseString+"\","+"攻击力:"+gongji+",防御力:"+fangyu+",职业技能"+zhiyeString);
Console.WriteLine();
}
catch
{
Console.WriteLine("请输入正确的选择内容");
}
#endregion
}
}
}
B.数组
1、一维数组
数据类型 [ ] 数组名称 = new 数据类型 [ 数组长度 ] {内容1,内容2.....};
数据类型 [ ] 数组名称 = {内容1,内容2......};
2.多维数组
数据类型 [ ,] 数组名称 = new 数据类型[行,列];
3.交错数组(了解)
定义:数组的数组,每行的列可以不同
数据类型 [ ] [ ] 数组名称 = new 数据类型 [行 ] [ ] ;
数据类型 [ ] [ ] 数组名称 = {{一维数组1},{一维数组2},.......};
int [ ][ ] arr1 = new int [3][ ] {new int [ ] {1,2,3} , new int [ ] {1,2} , new int [ ] {1}};
2.值类型和引用类型
1.string,数组,类时,为引用类型。其他为值类型
2.值类型在相互赋值时,将内容拷贝给对方,你变我不变
引用类型是相互赋值,你变我也变
3.两者不同的原因:
值类型存储在栈里 —— 系统分配,自动回收,小而快;
引用类型存储在堆里 —— 手动申请,大而慢;
4.string很特殊,有值类型的特征,他变我不变
3.函数
A.ref和out的使用
当传入的值类型参数在内部被修改 或 引用类型参数在内部重新申明的时候,外部也会发生改变。
a.ref的使用
//函数的设置
static void changeValue(ref int a) {
a = 3;
}
static void changeArray(ref int[] arr){
arr = new int[] {100,200,300};
}
//参数的传入
int a = 1;
changeValue(ref a);
Console.Writeline(a);//3
int[] arr1 = {1,2,3};
changeArray(ref arr1);
Console.WriteLine(arr[0]);//100
b.out的使用:将ref改为out
B.ref和out的区别
- ref传入的变量必须初始化,在内部可改可不改
- out传入的变量不必初始化,在内部必须赋值
4.变长参数和参数默认值
A.变长参数
关键字:params
static int add(params int[] arr){
int sum = 0;
for(int i = 0;i < arr.length;i++){
sum += arr[i];
}
return sum;
}
....
add(1,2,3,66,880,325,678);
- 可以传入n个对应类型的数值,n>=0
- parmas 后面跟的一定是数组,传入的数值会存入数组中
- 类型可以是任何类型
- 函数参数可以有别的参数 和 params修饰的参数 ,但是params修饰的参数必须是最后一个,且只能出现一次
B.参数默认值
- 有参数默认值的参数称为可选参数,可赋可不赋值
- 可以有多个参数默认值,但是必须放在普通参数后面
//函数设置
static void Eat(String food = "黄焖鸡米饭"){
Console.Write(food);
}
//函数的调用
Eat(); //黄焖鸡米饭
Eat("火锅"); //火锅
//当函数传入参数时,在函数的内部使用传入的参数,当函数没有传入参数时,就使用可选参数
5.重载函数
定义:在同一领域如struct或者class下,同一个函数名,传入的参数数量,类型,顺序不同的函数
注意:与返回值无关
适用范围:当不同类型有同一函数逻辑时就用重载函数
6.结构体
- 结构体内变量不能赋值
- 可以包含别的结构体,但是不能包含自己
- 结构体函数中可以直接使用结构体内部已申明的变量
- 结构体的构造函数:与结构体名字相同,无返回值,有参数,this.name = name,在外界传参时用 结构体名 名字 = new 构造函数名字(参数);
三,核心知识
1.类和对象
- 类是引用类型
- 类对象的基本语法
class Person{
}
Person p ;//只分配栈空间
Person p1 = NULL;//只分配栈空间
Person p2 = new Person();//开辟一个堆空间
2.成员变量 和 访问修饰符
成员变量:
- 成员变量可以是多个,可以赋初值,但大部分时间是不赋的,因为每个个体都不一样
- 如果要在类中申明一个和自己类型相同的成员变量,是不可以对它进行实例化的,会造成死循环
访问修饰符:
- public,公共的,内部和外部都可以访问
- private,私有的,只有内部可以使用(不写默认为private)
- protect,保护的,只有内部和子类可以使用
成员变量的使用和初始值:
- 值类型:数字类型都是0,bool类型是false
- 引用类型:null
3.成员方法
namespace ChengYuanBianLiang
{
internal class Program
{
class Person()
{
public String name;
public int age;
/// <summary>
/// 吃饭
/// </summary>
/// <param name="food"></param>
public void Eat(String food)
{
Console.WriteLine("{0}吃了{1}",name,food);
}
/// <summary>
/// 说话
/// </summary>
/// <param name="str"></param>
public void Spea(String str)
{
Console.WriteLine("{0}说{1}",name,str);
}
/// <summary>
/// 走路
/// </summary>
/// <param name="walk"></param>
public void Walk(bool walk)
{
if (walk)
Console.WriteLine("{0}正在走路",name);
else
Console.WriteLine("{0}正在休息",name);
}
}
class Student()
{
public String name;
public String ClassName;
public int number;
public void study(bool x)
{
if (x)
{
Console.WriteLine("{0}正在学习", name);
}
else
{
Console.WriteLine("{0}没有学习", name);
}
}
public void Eat(String food)
{
Console.WriteLine("{0}今天吃了{1}", name, food);
}
}
class Food()
{
public String name;
public int hotNums;
}
static void Main(string[] args)
{
Console.WriteLine("person类");
Person p = new Person();
p.name = "蔡徐坤";
p.age = 18;
p.Eat("黄焖鸡");
p.Spea("黄焖鸡真好吃");
p.Walk(false);
Console.WriteLine();
Console.WriteLine("Student类");
Student s = new Student();
s.name = "Jam";
s.ClassName = "计算机科学与技术一班";
s.number = 1;
s.study(true);
s.Eat("水饺");
Console.WriteLine();
Console.WriteLine("Food类");
Food f1 = new Food();
f1.name = "水饺";
f1.hotNums = 100;
Food f2 = new Food();
f2.name = "黄焖鸡";
f2.hotNums = 140;
}
}
}
4.构造函数,析构函数
A.构造函数
- 在实例化对象时,会用于初始化函数,如果不写则默认存在一个无参构造函数
- 如果只写了有参构造函数,那么无参构造函数会默认不存在
- 构造函数没有返回值 函数名必须和类名相同 没有特殊要求一般是public
- this用于表示当前被调用的自己
class People
{
public String name;
public int age;
//无参构造函数
public People()
{
name = "Jame";
age = 18;
}
//有参构造函数
public People(String name,int age)
{
this.name = name;
this.age = age;
}
}
B.析构函数
当引用内存的堆内存被回收时,就会调用析构函数(在Unity中几乎不会使用析构函数)
析构函数是当垃圾被回收时才会被调用
~类名
{
}
C.垃圾回收(GC)
- 垃圾回收过程是遍历堆上动态分配的所有对象
- 垃圾就是没有被任何变量,对象引用的内容
- GC只管堆(heap)内存的释放和回收,栈(stack)归系统管理,有它自己的生命周期
手动调用GC,当lading条过场景的时候就会调用GC
GC.Collect();
5.成员属性
A.成员属性的写法
在get中需要return内容,在set中需要value来传入内容
class Person
{
private string name;
private int age;
public string Name
{
get
{
return name;
}
set
{
//赋值
name = value;
}
}
static void Main(string[] args)
{
Person p = new Person();
p.Name = "mood"; //调用get()
Console.WriteLine(p.Name); //调用set()
}
B.加密与解密:存进去的东西和输入的东西不一样,起到了加密的作用
public string Name
{
get
{
return name - 5;
}
set
{
//赋值
name = value + 5;
}
}
C.成员属性在get和set前面加修饰符,解决3p的局限性
- 默认不加会使用属性申明时的访问权限
- 加的访问修饰符不能低于属性申明时的访问权限
- 不能都低于属性申明时的访问权限
D.get和set可以只有一个
当只给不得时,只有get;只改不得,只有set
E.自动属性
当一个属性只希望被外界只得不改,而且没有什么特殊要求的时候(比如解密加密,判断大小等等),就用自动属性,可以简约代码
//只得不改
public float Height
{
get;
private set;
}