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


    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
    {
    //遍历
    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;i0);i++)
    {
    for(int j=0;j1);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;i0);i++)
    {
    for(int j=0;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("********************************");
    }
    }
    }

    image

    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]);//改变数值

    image

    区别:

    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
    {
    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 - 内部的 只有在同一个程序集的文件中,内部类型或者是成员才可以访问

    既然都看到这里了,那就给个👍吧!
    小小一赞,给作者的莫大的鼓励!
    关注我,我会每天更新C#学习笔记,从入门到进阶,一起来学习啊!!!

  • 相关阅读:
    Linux性能优化--性能追踪:受CPU限制的应用程序(GIMP)
    幂级数和幂级数的和函数有什么关系?
    ionic+vue+capacitor系列笔记--常用操作代码合集(图片引用,axios跨域配置,去除按钮波纹)
    opencv c++ 二值图像、阈值计算方法、全局阈值、自适应阈值
    全真模拟题!PMP提分必练
    uniapp h5 echarts 打包后图表点击失效/及其他失效
    NPS(cnlh)内网穿透弱口令与登录爆破漏洞复现-内附自动化脚本
    科学计算库 —— Matplotlib
    抖音怎么一次性隐藏全部视频
    Himall商城Web帮助类删除、获取设置指定名称的Cookie特定键的值(1)
  • 原文地址:https://www.cnblogs.com/TonyCode/p/17757597.html