C# 常量 结构体 委托

常量

const double PI = 3.1415926;

常量名命名一般使用大写字母

枚举类型

开发一个游戏,游戏角色有法师(Mage)、射手(Archer)、刺客(Assassin)、坦克(Tank)、铺助(Support)、战士(Warrior),等不同类型。

❓如何存储游戏角色

  • 使用int类型 :创建一套规则,提前为各个类型角色绑定一个数字标识
  • 使用枚举类型

什么是枚举类型?

枚举类型是一种特殊的值类型,可以在枚举类型中定义一组命名的数值常量。

如何声明枚举类型?

enum <enum_name>
{
	value1,
	value2,
	value3,
	...
	valuen
}

默认情况下,

  • 每个枚举成员对应的数值都是int类型的
  • 按照枚举成员的生命顺序,自动按照0、1、2 ······ 进行常量赋值。

可以指定其他的整数类型代替默认类型,也可以显示指定每一位枚举成员的对应值:

public enum BorderSide : byte { Left = 1, Right, Top = 10, Bottom }

上面的开发场景利用枚举类型就可以这样来完成:

enum RoleType { Mage, Archer, Assassin, Tank, Support, Warrior }
static void Main(string[] args)
{
    RoleType Top = RoleType.Tank;
    Top = RoleType.Warrior;
}

image-20230502164650057

  • 枚举类型的实例可以与它对应的整数值相互显式转换

  • RoleType Top = RoleType.Tank;
    int i=(int)Top;	// 3
    
  • 也可以显式将一个枚举类型转换为另一个

  • 由于枚举类型可以和它对应的整数类型相互转换,因此枚举的真实值可能超出枚举类型成员的数值范围,在使用过程中需要考虑类型安全问题

结构体

我们日常使用的变量,一般都是某一个单一的信息,比如一个学生的信息:

age
name
grade
studylD

❓对于一个学生信息的话,我们怎么对这些信息进行一个整合呢?

  • 结构体

什么是结构体?

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

结构体的作用就是把某一类的变量进行整合,组成一个新的数据类型,相当于一个新的信息。

如何声明结构体?

struct <struct_name>
{
	访问权限 type typename
	访问权限 ype typename
}

关于学生信息,就可以这样来存储:

struct Studentinfo
{
    public int age;
    public string name;
    public int grade;
    public int studylD;
}

static void Main(string[] args)
{
    Studentinfo xiaoming = new Studentinfo();
    xiaoming.age = 10;
    xiaoming.grade = 1;
    xiaoming.name = "小明";
    xiaoming.studylD = 107963212;
    Console.ReadKey();
}

结构体的构造语义如下:

  • 结构体隐式包含一个无法重写的无参数构造器。此构造函数不允许删除和重定义,并且这个无参数的构造函数会一直存在,并不会因为定义了其他带参数的构造函数就消失,这一点和类不同。

    • 构造器的作用是初始化对象,构造器也就是构造函数,通俗的讲就是你在实例化结构体也就是创建结构体对象时是new Studentinfo()还是new Studentinfo(10,1,"小明",107963212)
    • 构造函数(C# 编程指南)
  • 定义结构体的构造器时,必须显式为每一个字段赋值。

结构体构造函数(简单概述)

结构类型都有一个预定义的,没有参数的构造函数,这点与类是一样的。

看这个场景:

struct A
{
    static A()
    {
        Console.WriteLine("I am A.");
    }
    public void Fun()
    {

    }
}
static void Main(string[] args)
{
    A a = new A();
    a.Fun(); //结构的实例成员被引用
    Console.ReadKey();
}

输出结果为:I am A.

当你把a.Fun();注释掉以后再次运行程序你会发现程序不会输出任何东西。

❓那么结构体的静态构造函数何时触发呢

答案是:结构体的实例成员被引用,结构体的静态成员被引用,结构体显式声明的构造函数被调用。

就上上面说的:结构体隐式包含一个无法重写的无参数构造器。此构造函数不允许删除和重定义,并且这个无参数的构造函数会一直存在,并不会因为定义了其他带参数的构造函数就消失,这一点和类不同。

我们拿类来做比较:

struct Name
{
    public string firstName;
    public string lastName;
    public string FullName()
    {
        return firstName + lastName;
    }
    //Name()
    //{
    //    Console.WriteLine("无参构造函数");
    //}
}
class _Name
{
    public string firstName;
    public string lastName;
    public string FullName()
    {
        return firstName + lastName;
    }
    public _Name()
    {
        Console.WriteLine("无参构造函数");
    }
}
static void Main(string[] args)
{
    Name name = new Name();
    name.firstName = "三";
    name.lastName = "张";
    Console.WriteLine(name.FullName());
    _Name name1 = new _Name();

    Console.ReadKey();
}

结构体Name中的Name()构造函数在取消注释后编译器会报错,但是当你将Name()改成带参的构造函数后编译器就不会提示错误了。这个时候,按照类的思路来讲,我们在创建结构体Name的对象时应该要完成结构体带参构造的所有字段的初始化,否则就会报错。也就是说我们在创建Name结构体对象时应该这样写:

Name name = new Name("三","张");

但是我们发现,我们写Name name = new Name();也是没问题的,之所以为问题就是因为结构体隐式包含一个无法重写的无参数构造器。

我们换到类里面,将无参的构造函数改为带参数的,此时_Name name1 = new _Name();就会报错。

image-20230502185228652

此外,我们还可以发现,类的无参构造函数在初始化对象的时候就会调用,而结构体的静态默认无参构造函数则不会,只有在上述三种情况中才会被调用。

image-20230502185720358

[C# 结构体](https://www.cnblogs.com/arxive/p/5799245.html)

实例构造函数(C# 编程指南)

C# 结构体(Struct)

结构体函数

struct Name
{
    public string firstName;
    public string lastName;
    public string FullName()
    {
        return firstName + lastName;
    }
}
static void Main(string[] args)
{
    Name name = new Name();
    name.firstName = "三";
    name.lastName = "张";
    Console.WriteLine(name.FullName());
    Console.ReadKey();
}

小练习

定义一个Vector3的结构体(这个结构体可以用来表示坐标,可以表示向量),在里面定义一个Distance方法,用来取得一个向量的长度的。

冷知识:向量长度 可以百度 一个向量的长度等于他和他自己的内积的平方根

struct Vector3
{
    public double x; public double y; public double z;
    public double Distance()
    {
        return Math.Sqrt(z * z + x * x + y * y);
    }
}
static void Main(string[] args)
{
    Vector3 v1 = new Vector3();
    v1.x = 4;
    v1.y = 5;
    v1.z = 6;
    Console.WriteLine(v1.Distance());
    Console.ReadKey();
}

委托(简单概述)

委托delegate是一种存储函数引用的类型。

委托的定义指定了一个返回类型和一个参数列表。

定义了委托之后,就可以声明该委托类型的变量,接着就可以把一个返回类型跟参数列表跟委托一样的函数赋值给这个变量。

简单来讲,委托delegate是一种存储数引用的类型。委托的定义指定了一个返回类型和一个参数列表定义了委托之后,就可以声明该委托类型的变量,接着就可以把一个返回类型跟参数列表跟委托一样的丽数赋值给这个变量。

static double Multiply(double param1, double param2)   
{
    return param1 * param2;
}
static double Divide(double param1, double param2)
{
    return param1 / param2;
}
delegate double MyDelegate(double param1, double param2);
static void Main(string[] args)
{
    MyDelegate delegate1;
    delegate1 = Multiply;
    Console.WriteLine(delegate1(2,4));  // 8
    delegate1 = Divide;
    Console.WriteLine(delegate1(4,2));   // 2
    Console.ReadKey();
}

可以理解为定义声明一种特殊的函数,只有个声明,没有具体的函数体内容,函数的类型是delegate,需要用同参数类型、数量以及同返回值的函数赋值给委托变量。

internal class Program
{
    delegate void OnDieDelegate();
    static void PLay(OnDieDelegate onDie)
    {
        Console.WriteLine("做任务");
        Console.WriteLine("玩家正在战斗");
        Console.WriteLine("死");
        if(onDie != null)
        {
            onDie();
        }
    }
    static void ShowDieUI()
    {
        Console.WriteLine("显示游戏死亡后的UI");
        Console.WriteLine("返回首页UI");
    }

    static void Main(string[] args)
    {
        PLay(ShowDieUI);
        PLay(null);
        Console.ReadKey();
    }
}
posted @ 2023-05-02 20:48  PixelKiwi  阅读(438)  评论(0编辑  收藏  举报