C#学习笔记–复杂数据类型、函数和结构体

  • C#学习笔记–复杂数据类型、函数和结构体已关闭评论
  • 104 次浏览
  • A+
所属分类:.NET技术
摘要

特点:多个数据变量地一个集合体,可以自己命名种类:枚举、数组和结构体


C#基础

复杂数据类型

特点:多个数据变量地一个集合体,可以自己命名

种类:枚举、数组和结构体

  • 枚举:整型常量的集合
  • 数组:任意变量类型的顺序存储的数据集合
  • 结构体:任意变量类型的数据组合成的数据块

枚举

枚举可以方便表示对象的各种状态,本质还是一种变量。

例如我们可以用枚举来表示怪物的种类、玩家的动作状态(静止、战斗、受伤......)

枚举的声明:

enum E_MonsterType//命名E_XXX {      Normal,//0      Boss,//1 自动根据上一个数值顺延 } enum E_PlayerType {       Main,      Other, } 

枚举类型的使用:

//自定义的枚举类型  变量名 = 默认值;(自定义的枚举类型.枚举项) E_PlayerType playerType = E_PlayerType.Other;  if( playerType == E_PlayerType.Main ) {     Console.WriteLine("主玩家逻辑"); } else if(playerType == E_PlayerType.Other) {     Console.WriteLine("其它玩家逻辑"); } //枚举也常常与switch语句做配合   //枚举和switch是天生一对 E_MonsterType monsterType = E_MonsterType.Boss; switch (monsterType) {     case E_MonsterType.Normal:         Console.WriteLine("普通怪物逻辑");         break;     case E_MonsterType.Boss:         Console.WriteLine("Boss逻辑");         break;     default:         break; } 

枚举类型转换:

  • 枚举与int互转:
int i=(int) playerType; playerType=0; 
  • 枚举与string互转:
playerType=(E_PlayerType)Enum.Paese(typeof(E_PlayerType),"other"); string str=playerType.ToSring(); 

数组

数组是存储同一种特定变量类型的有序数据集合,内存上的连续存储。

一维数组

//数组声明 int[] arr1;//未分配内存地址 int[] arr2=new int[5];//元素默认值0 int[] arr3=new int[5]{1,2,3,4,5}; int[] arr4=new int[]{1,2,3}; int[] arr5={1,2,3,4,5,6};  //数组的使用 arr2.Length;//长度 arr2[0];//获取数组中的元素 arr2[2]=99;//修改内容 //数组的遍历 for(int i=0;i<arr2.Length;i++) {     //遍历      Console.WriteLine(arr2[i]); }  //数组的自定义扩容 //声明新的大容量数组,把旧有的进行复制转移 int[] array2 = new int[6]; //搬家 for (int i = 0; i < array.Length; i++) {     array2[i] = array[i]; } array = array2;  //自定义实现数组的删除元素 int[] array3 = new int[5]; //搬家 转移 for (int i = 0; i < array3.Length; i++) {     array3[i] = array[i]; } array = array3;   //查找数组中元素 //只有遍历数组 找到合适的则终止遍历 int a = 3; for (int i = 0; i < array.Length; i++) {     if( a == array[i] )     {         Console.WriteLine("和a相等的元素在{0}索引位置", i);         break;     } }  

多维数组(二维数组)

//二维数组 //声明 int[,] arr; int[,] arr2=new int[3,4]; int[,] arr3=new int[3,4]{{0,1,2,3},//给元素内容  告诉维度 元素个数                          {0,1,2,3},                          {0,1,2,3}}; int[,] arr4=new int[,]{{0,1,2,3},//给元素内容 告诉维度                          {0,1,2,3},                          {0,1,2,3}}; int[,] arr5={{0,1,2,3},    //直接给元素内容              {0,1,2,3},              {0,1,2,3}};  //使用 //获取长度 arr3.GetLength(0);//行的长度 arr3.GetLength(1);//列的长度  //获取元素 arr3[1,1];//第一行第一列的元素 //遍历二维数组 for(int i=0;i<arr3.GetLength(0);i++) {     for(int j=0;j<arr3.GetLength(1);j++)     {         //访问 具体元素     } } //增加数组元素 //思想:新建一个大容量的数组,将小的数组元素复制到大的数组中 //最后修改小的数组索引指向大的数组 实现“数组扩容” //删除数组元素(同增加) //查找数组中的元素(遍历比对) 

交错数组

交错数组区别于多维数组,是数组的数组,一维数组元素也是数组,且长度不必完全相同。

//交错数组 //声明 int [][] arr1; int [][] arr2=new int[3][];//不可以规定列的长度 int [][] arr3=new int[3][]{     new int[] {1,2,3,4},     new int[] {1,2,3},     new int[] {1} };//体会数组的数组的含义! int [][] arr4=new int[][]{     new int[] {1,2,3,4},     new int[] {1,2,3},     new int[] {1} };  int [][] arr5={//也可以直接赋值     new int[] {1,2,3,4},     new int[] {1,2,3},     new int[] {1} };  //数组的使用 //长度 arr3.GetLength(0);//行数 arr3[0].Length;//第0行的长度  //获取元素 arr3[0][2]; //遍历 for(int i=0;i<arr3.GetLength(0);i++) {     for(int j=0;j<arr3[i].Legth;j++)     {         //访问元素         Console.WriteLine(arr3[i][j]);     } } 

值类型和引用类型

值类型的数值存储在(系统分配,自动回收GC,小而快)中、引用类型的存储在(大而慢,需手动分配与回收)中,栈中只存储其指针;

值类型在赋值时候将数值拷贝,而引用赋值修改引用指向的内存位置。

值类型:(14+2(枚举、结构体))

  • 无符号整型:byte ushort uint ulong
  • 有符号整型:sbyte short int long
  • 浮点数: float double decimal
  • 特殊类型:bool char
  • 结构体
  • 枚举:enum

引用类型:(5种)

string 、数组、类、接口、委托

函数

函数本质是封装的代码块,提升代码的复用率,抽象出具体的执行过程。

函数只能存在 structclass

//函数出现在stuct与class中 //函数种类 //1 无参数 无返回值 void sayHellow() {     Console.WriteLine("Hello World"); } //2 有参数 无返回值 void sayHellow(string name) {     Console.WriteLine("Hello,"+name); } //3 有参数 有返回值 int Add(int a,int b) {     return a+b; } //4 无参数 有返回值 string getMyName() {     return "TonyChang"; } 

ref 和 out

使用其可以解决在函数内部改变函数外部的变量的数值的问题。

(本质是传参数过程中传的是数值或引用是否完全绑定到同一个数值/内存空间中)

//ref的使用 using System; namespace CSharpLearn1 {     class Program     {         static void ChangeValue(int value)         {             value = 3;         }         static void ChangeArrayValue(int[] arr)          {             arr[0] = 33;         }         static void ChangeArray(int[] arr)         {             arr = new int[] {666,777,888,999 };         }         static void ChangeValueRef(ref int value)         {             value = 3;         }         static void ChangeArrayValueRef(ref int[] arr)         {             arr[0] = 33;         }         static void ChangeArrayRef( ref int[] arr)         {             arr = new int[] { 666, 777, 888, 999 };         }         static void Main(string[] args)         {                          int a1 = 1;             Console.WriteLine("a1原数值{0}", a1);             ChangeValue(a1);             Console.WriteLine("调用ChangValue函数之后a1的数值{0}", a1);//未改变数值             ChangeValueRef(ref a1);             Console.WriteLine("a1调用ChangValueRef函数之后a1的数值{0}", a1);//改变数值             Console.WriteLine("********************************");              int[] arr1 = { 100, 200, 300 };             Console.WriteLine("arr1[0]原数值{0}", arr1[0]);             ChangeArrayValue(arr1);             Console.WriteLine("调用ChangArrayValue函数之后arr1[0]的数值{0}", arr1[0]);//改变数值             Console.WriteLine("********************************");              int[] arr2 = { 100, 200, 300 };             Console.WriteLine("arr2[0]原数值{0}", arr2[0]);             ChangeArray(arr2);             Console.WriteLine("调用ChangArrayValue函数之后arr2[0]的数值{0}", arr2[0]);//未变数值             ChangeArrayRef(ref arr2);             Console.WriteLine("调用ChangArrayValueRef函数之后arr2的数值{0}", arr2[0]);//改变数值             Console.WriteLine("********************************");              int[] arr11 = { 100, 200, 300 };             Console.WriteLine("arr11[0]原数值{0}", arr11[0]);//改变数值             ChangeArrayValueRef(ref arr11);             Console.WriteLine("调用ChangArrayValueRef函数之后arr[0]的数值{0}", arr11[0]);//改变数值             Console.WriteLine("********************************");         }     } } 

C#学习笔记--复杂数据类型、函数和结构体

Out

//添加两个OUt修饰参数的函数    static void ChangeValueOut(out int value)     {         value = 3;     }     static void ChangeArrayOut(out int[] arr)     {         arr = new int[] { 666, 777, 888, 999 };     } //添加到Main函数中   int a1 = 1;             Console.WriteLine("a1原数值{0}", a1);             ChangeValue(a1);             Console.WriteLine("调用ChangValue函数之后a1的数值{0}", a1);//未改变数值             ChangeValueOut(out a1);             Console.WriteLine("a1调用ChangValueOut函数之后a1的数值{0}", a1);//改变数值             Console.WriteLine("********************************");             int[] arr1 = { 100, 200, 300 };             Console.WriteLine("arr1[0]原数值{0}", arr1[0]);             ChangeArray(arr1);             Console.WriteLine("调用ChangArray函数之后arr1[0]的数值{0}", arr1[0]);//未改变数值             ChangeArrayOut(out arr1);             Console.WriteLine("调用ChangArrayOut函数之后arr1[0]的数值{0}", arr1[0]);//改变数值  

C#学习笔记--复杂数据类型、函数和结构体

区别:

  1. ref传入的变量必须初始化 out不必
  2. out传入的变量必须在内部进行赋值 ref不必

理解:ref在传入时候已经有初始值,所以在内部可以不作修改,

​ out在传入时候可能未有初始值,所以要保证有效,在内部必须进行赋值。

函数的变长参数关键字 ---params

  1. 其后只能跟数组
  2. 数组类型可以为任意类型
  3. 函数参数列表中只能出现一个params,并且修饰的参数只能在末尾出现
//函数变长参数关键字 params后必须为数组 //求n个int的和 int Sum(params int[] arr) {     int sum=0;     for(int i=0;i<arr.Length;i++)     {         sum+=arr[i];     }     return sum; } void Chat(string name,params string[] things) {     //函数体... } 

函数的参数默认值

函数参数列表中可以有多个参数,有默认值的参数一定在普通参数的后面

void Speak(string thing="我没什么可说的了") {     Console.WriteLine(thing); } //调用 Speak(); Speak("我想说,,,,"); 

函数重载:

在同一语句块中,函数名字相同,函数的参数列表不同(参数类型不同或参数的个数不同,二者均相同则参数顺序不同)

//函数重载 //函数的参数数量不同  int Sum(int a,int b) {     return a+b; } int Sum(int a,int b,int c) {     return a+b+c; } // 参数 数量相同 类型不同 float Sum(int a,int b) {     return a+b; } float Sum(float f1,float f2) {     return f1+f2; } //参数 数量相同 类型相同 顺序不同 float Sum(float f,int i) {     return f+i; } float Sum(int i,float f) {     return f+i; } //ref 和 out 改变参数类型 与普通的函数构成重载 //ref 和out 算作一类 自身不可互相构成重载 int Sum(int a,int b) {     return a+b; } int Sum(ref int a,int b) {     return a+b; } //params 可以作为重载 //但是 参数默认值不可构成重载 

递归函数

函数自己调用自己,递归有递归基与结束调用的条件.

//递归打印0-10 void Fun(int a) {     if(a>10)         return;     Console.WriteLine(a);     a++;     Fun(a); } //递归----求某一数的阶乘 int getFactorial(int a) {     //结束条件     if(a==1)         return 1;     //递归基     return a*getFactorial(a-1); } //递归----求1!+2!+3!+···+10! int getFactorialSum(int num) {     if(num==1)         return 1;     return getFactorial(num)+getFactorial(num-1); } //递归--- //一根竹竿长100m,每天砍掉一半,求第十天的长度是多少? void getLong(float length,int day=0) {     length/=2;     if(day==10)     {         Console.WriteLine("第十天砍后的竹子长度为{0}米",length);     }     ++day;     getLong(length,day); } //---递归打印1-200 //递归+短路 bool Fun5(int num) {     Console.WriteLine(num);     return num==200||Fun5(num+1);//第一个为条件真 便会短路 } 

结构体

结构体是数据与方法的集合,在namespace

命名规则:帕斯卡命名法(首字母均大写)

构造函数:

  1. 无返回值
  2. 必须与结构体名字相同
  3. 必须有参数
  4. 如有构造函数,必须把所有的变量进行赋值
//结构体 struct Student {     //不可以包含自身类型的结构体--Student  s; 报错!     //姓名:     public string name;     //年龄     public int age;//数值变量不可以直接初始化     public bool sex;     //构造函数(默认有一个无参构造函数,若有构造函数则默认的构造函数失效)     //对变量进行初始化     public Student(string name,int age,bool sex)     {         this.name=name;         this.age=age;         this.sex=sex;     }     //方法     public void Speak()     {         Console.WriteLine("你好");     } }  //结构体的使用 Student s1; s1.name="Tony"; s1.age=18; s1.sex=true; s1.Speak(); 

访问修饰符

  1. public
  2. private(默认不写算私有)
  3. protect 继承的可以访问
  4. internal - 内部的 只有在同一个程序集的文件中,内部类型或者是成员才可以访问