HOME
BLOG
Class专题(2)
9月 03 2022

结构体 Struct

  • 小概念:struct + name{...} ,便声明了一个结构体。

  • 结构体是 值类型数据结构。它使得一个单一变量可以存储各种数据类型的相关数据。

  • struct & class 的异同

    • 相同点:

      • (1)静态构造函数

        • 都支持
      • (2)自定义函数

        • 都支持
      • (3)const 修饰的变量

        • 结构体 和 类 对于 const 修饰的变量的使用方式是一样的
    • 不同点:

      • (1)构造函数:

        • 结构体 不允许定义无参构造函数,只允许定义有参构造函数;但是 类 是都可以的
      • (2)析构函数

        • 结构体 不允许定义析构函数;但是 类 是可以的
      • (3)函数的修饰符

        • 结构体 不允许声明为 virtual 虚函数;但是 类 是可以的
        • 结构体 不允许声明为 protected 受保护的函数;但是 类 可以
      • (4)类型修饰符

        • 结构体 不允许声明为 abstract;但是 类 是可以的
      • (5)关于变量

        • (a)普通变量

          • 结构体 声明的全局普通变量(不带修饰符的),不能在 声明式 直接赋值,只能在 构造函数 里边赋值;类 哪里都可以
        • (b)readonly

          • 结构体声明的 全局readonly 变量,只能在构造函数里边赋值;类 都可以
      • (6)关于继承

        • 结构体 之间不可以互相继承;但是类与类之间是可以继承的(sealed密封类除外)。
      • (7)使用上

        • (a)访问变量

          • 结构体 访问成员变量,给变量显示赋值,就可直接访问;而 类 必须实例化对象才可以访问
          • 结构体 如果不通过 new 初始化,是不可以直接访问其内部变量的( const 除外)
        • (b)访问函数

          • 结构体变量 和 类对象 必须进行初始化,才可以访问
      • (8)new

        • (a)结构体属于 值类型,结构体的 new ,并不会在堆上分配内存,仅仅是调用结构体的构造函数初始化而已。

        • (b)类属于 引用类型,类的 new ,会在堆上分配内存,而且也会调用类的构造函数进行初始化。

演示:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

struct BaseStruct
{

}

/*abstract*/ struct MyStruct //: BaseStruct
{
    public int a;
    //public const string str;// = "20";
    public readonly string str2 ;

    public MyStruct(int value) 
    { 
        a = value;
        //str = "20";
        str2 = "20";
    }
    //~MyStruct() { }
    static MyStruct() { }

    public  void Show() { }

    // public virtual void Show2() { }
    // protected void Show3() { }
}

class BaseClassT
{

}
/*abstract*/ class MyClass20 : BaseClassT
{
    public int a = 2000;
    //public const string str;// = "20";
    public readonly string str2 /*= "20"*/;

    public MyClass20( /* int value */ ) 
    {
        //str = "20"; 
        str2 = "300";
    }
    ~MyClass20() { }
    static MyClass20() { }

    public void Show() { }

    public virtual void Show2() { }

    protected void Show3() { }
}

public class TStruct : MonoBehaviour
{
    void Start()
    {
        MyClass20 myClass20 = new MyClass20();
        // int a = myClass20.a;
        myClass20.Show();

        MyStruct myStruct = new MyStruct();
        //myStruct.a = 20000;
        //int b = myStruct.a;
        myStruct.Show();
    }
}

is & as 显式 / 隐式转换(数据类型转换)

  • 小概念:

    • is :检查对象类型的兼容性,并返回结果 true(false)

    • as :检查对象类型的兼容性,并返回转换结果,如果不兼容则返回 null

  • 前置知识:

    • 引用类型(堆上): stringint[]classinterface

    • 值类型(栈上): byte(u)short(u)int(u)longbool enumstruct

演示:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/*
 * 前置知识2:
 *          short       -32,768 ~ 32,767
 *          int         -2,147,483,648 ~ 2,147,483,647
 *          float       7 位小数
 *          double      15 ~ 16 位小数
 * 
 * 
 * is
 *      可检测 值类型 和 引用类型,成功返回 true;否则返回 false
 * as
 *      as 首先会判断 源数据类型 是否是 目标数据类型,不是的话,编译器直接报错
 *      as 转换成功 返回源数据类型存储的数据,否则,返回 null
 *      
 *      
 * 强制类型转换(显式类型转换)
 *    高精度 --》 低精度  需要强制类型转换
 *    注意:
 *        高精度数据类型 转换为 低精度数据类型时,若要转换成功需要 高精度数据类型的 位数 <= 低精度的数据类型
 * 
 * 自动类型转换(隐式类型转换)
 *    低精度 --》 高精度 系统自动转换
 */

public class BaseTemp
{

}

public class SonTemp : BaseTemp
{

} 

public class TypeChange : MonoBehaviour
{
    void Start()
    {
        /*
        int a = 1234567;
        short b = (short)a;
        Debug.Log(b);
        */

        /*
        short a = 1234;
        int b = a;
        short c = 32768;
        */

        /*
        string a = "abc";
        int b = 123;

        bool c =  a is int; // a is string
        if (c)
        {
            Debug.Log("a 是 string 类型的");
        }
        else
        {
            Debug.Log("a 不是 string 类型的");
        }
        */

        /*
        string a = "abc";
        int b = 123;

        string c = a as string;
        Debug.Log(c);


        string c = a as int;
        Debug.Log(c);


        int[] c = a as int[];
        Debug.Log(c);


        int[] d = { 1, 2, 3 };
        int[] c = d as int[];

        if (c != null)
        {
            Debug.Log(c.Length);
        }
        */

        /*
        SonTemp son = new SonTemp();
        if (son as SonTemp != null)
        {
            Debug.Log("son as SonTemp");
        }
        if (son as BaseTemp != null)
        {
            Debug.Log("son as BaseTemp");
        }
        */
    }
}

什么是装箱 & 拆箱

  • 小概念:

    • 装箱: 值类型 –》 引用类型

    • 拆箱: 引用类型 –》 值类型

演示:

        int a = 20;
        object b = (object)a; // 装箱,发生GC 内存分配
        object d = a;

        int c = (int)b; // 拆箱

值类型与引用类型的内存模型

推荐阅读博客:深入理解C#中的堆(heap)与栈(Stack),一次性全部掌握

演示:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Monster
{
    public string name = "骷髅兵";
    public int hp = 100;
}

public class HeapStack : MonoBehaviour
{
    void Start()
    {
        //Example1();
        //Example2();
        //Example3();
        Example4();
    }

    void Example1()
    {
        int a = 10;
        int b = 20;
        short c = 30;
    }

    void Example2()
    {
        int a = 20;
        string b = "Vip";
        string c = "Skill";
        b = c;
        Debug.Log(b);
    }

    void Example3()
    {
        Monster monster = new Monster();
    }

    void Example4()
    {
        Monster[] monsters = { new Monster(), new Monster(), new Monster() };
        Monster monster1 = monsters[0];
        monster1.name = "石头人";
        Monster monster2 = monsters[0];
        monster2.name = "嗜血蝙蝠";
        Debug.Log(monster1.name);
    }
}


👾 - Morikiiii - 👾

C# Study