文章目录
枚举
枚举是一组命名整型常量。枚举类型是使用 enum 关键字声明的。
C# 枚举是值类型,存放在栈中。枚举包含自己的值,且不能继承或传递继承。
枚举的优点:
- 枚举能够使代码更加清晰,它允许使用描述性的名称表示整数值。
- 枚举使代码更易于维护,有助于确保给变量指定合法的、期望的值。
- 枚举使代码更易输入。
枚举的种类:
- 简单枚举
- 标志枚举(多选枚举)
- 简单枚举
- 枚举使用enum关键字来声明,与类同级。枚举本身可以有修饰符,但枚举的成员始终是公共的,不能有访问修饰符。枚举本身的修饰符仅能使用public和internal。
- 枚举是值类型,隐式继承自System.Enum,不能手动修改。System.Enum本身是引用类型,继承自System.ValueType。
- 枚举都是隐式密封的,不允许作为基类派生子类。
- 枚举类型的枚举成员均为静态,且默认为Int32类型。
- 每个枚举成员均具有相关联的常数值。此值的类型就是枚举的底层数据类型。每个枚举成员的常数值必须在该枚举的底层数据类型的范围之内。如果没有明确指定底层数据类型则默认的数据类型是int类型。
- 枚举成员不能相同,但枚举的值可以相同。
枚举的定义和使用:
enum Week
{
Monday = 1,
Tuesday = 2,
Wednesday = 3,
Sunday = 0,
Everyday = 1 // 成员的值可以设置成一样的,但是成员不行
}
Console.WriteLine((int)Week.Monday); // 获取值
显式指定枚举类型:枚举值默认从0开始,逐个递增。
enum sex : byte // 显式指定枚举的底层数据类型
{
male, // 0
female // 1
}
枚举的各种使用方法:
class Program
{
static void Main(string[] args)
{
Console.WriteLine(Enum.GetName(typeof(Man),1)); // 刘备 (由值获取成员名)
string[] array1 = Enum.GetNames(typeof(Man));
Console.WriteLine(array1[1]); // 关羽(按数组下标取成员名)
Array array2 = Enum.GetValues(typeof(Man));
Console.WriteLine(array2.GetValue(1)); // 关羽(按数组下标获取枚举值)
Type t = Enum.GetUnderlyingType(typeof(Man));
Console.WriteLine(t); // 输出 Int32(获取枚举类型)
Console.WriteLine(Man.刘备.ToString());// 获取成员名
// 由值获取内容
int i = 1;
string Name = Enum.Parse(typeof(Man), i.ToString()).ToString(); //此时 Name="刘备"
Console.WriteLine(Name);
// 由值获取内容
string Name2 = "关羽";
int j = Convert.ToInt32(Enum.Parse(typeof(Man), Name2)); //此时 j=2
Console.WriteLine(j);
Console.ReadKey();
}
}
enum Man
{
刘备 = 1,
关羽 = 2,
张飞 = 3
}
- 标志枚举(多选枚举)
标志枚举(多选枚举)使枚举可以实现多选,写法是要在顶部加[System.Flags]特性进行声明。
class Program
{
static void Main(string[] args)
{
var man = Week.White | Week.Rich; //赋值为011 计算方法001或上010,结果是011
Console.WriteLine((int)man);
if ((man & Week.White) == Week.White) // 011 按位与 001,每个位对比,当两边都为1时结果为1,所以结果为 001
{
Console.WriteLine("此人白");
}
else
{
Console.WriteLine("此人黑");
}
Console.ReadKey();
}
}
[System.Flags]
public enum Week
{
White = 1, //001
Rich = 2, //010
Beauty = 4 //100
}
- Enum类
C#提供类一个类来方便操作枚举,下面给出这个类的常用方法:
C#索引器
C#允许一个对象可以像数组一样使用下标的方式访问,下标可以是int,也可以是string,使用方法为在类中写一个this属性。索引器又称为带参属性。当被封装的字段是一个数组的时候,可以考虑使用索引器,操作方便且相对安全。
- 使用索引器可以用类似于数组的方式为对象建立索引。
- get 访问器返回值。set 访问器分配值。
- this 关键字用于定义索引器。
- value 关键字用于定义由 set 索引器分配的值。
- 索引器不必根据整数值进行索引,由您决定如何定义特定的查找机制。
- 索引器可被重载。
- 索引器可以有多个形参,例如当访问二维数组时。
public string this[int index]
{
get
{
string tmp = myList[index];
return tmp;
}
set
{
myList[index] = value;
}
}
// 正常的new,使用下标获取内容
ClassX x = new ClassX();
a[1] = "asdfasdf";
- 使用泛型的索引器
class SampleCollection<T>
{
private T[] arr = new T[100];
public T this[int i]
{
get
{
return arr[i];
}
set
{
arr[i] = value;
}
}
}
// 如何使用这个索引器
class Program
{
static void Main(string[] args)
{
SampleCollection<string> stringCollection = new SampleCollection<string>();
stringCollection[0] = "Hello, World";
System.Console.WriteLine(stringCollection[0]);// Hello, World
}
}
索引器与数组的比较:
- 索引器的索引值不受类型限制。用来访问数组的索引值一定是整数,而索引器可以是其他类型的索引值。
- 索引器允许重载,一个类可以有多个索引器。
- 索引器不是一个变量没有直接对应的数据存储地方。索引器有get和set访问器。
- 索引器允许类和结构的实例按照与数组相同的方式进行索引,索引器类似与属性,不同之处在于他们的访问器采用参数。被称为有参属性。
索引器与属性的比较:
- 标示方式:属性以名称来标识,索引器以函数签名来标识。
- 索引器可以被重载。属性则不可以被重载。
- 属性可以为静态的,索引器属于实例成员,不能被声明为static。
结构体
在 C# 中,结构体是值类型数据结构。它使得一个单一变量可以存储各种数据类型的相关数据。struct 关键字用于创建结构体。
- 结构体定义与使用
为了定义一个结构体,您必须使用 struct 语句。struct 语句为程序定义了一个带有多个成员的新的数据类型。
例如,您可以按照如下的方式声明 Book 结构:
struct Books
{
public string title;
public string author;
public string subject;
public int book_id;
};
下面的程序演示了结构的用法:
using System;
using System.Text;
struct Books
{
public string title;
public string author;
public string subject;
public int book_id;
};
public class testStructure
{
public static void Main(string[] args)
{
Books Book1; /* 声明 Book1,类型为 Books */
Books Book2; /* 声明 Book2,类型为 Books */
/* book 1 详述 */
Book1.title = "C Programming";
Book1.author = "Nuha Ali";
Book1.subject = "C Programming Tutorial";
Book1.book_id = 6495407;
/* book 2 详述 */
Book2.title = "Telecom Billing";
Book2.author = "Zara Ali";
Book2.subject = "Telecom Billing Tutorial";
Book2.book_id = 6495700;
/* 打印 Book1 信息 */
Console.WriteLine( "Book 1 title : {0}", Book1.title);
Console.WriteLine("Book 1 author : {0}", Book1.author);
Console.WriteLine("Book 1 subject : {0}", Book1.subject);
Console.WriteLine("Book 1 book_id :{0}", Book1.book_id);
/* 打印 Book2 信息 */
Console.WriteLine("Book 2 title : {0}", Book2.title);
Console.WriteLine("Book 2 author : {0}", Book2.author);
Console.WriteLine("Book 2 subject : {0}", Book2.subject);
Console.WriteLine("Book 2 book_id : {0}", Book2.book_id);
Console.ReadKey();
}
}
- 结构体的特点
C# 中的结构有以下特点:
- 结构可带有方法、字段、索引、属性、运算符方法和事件。
- 结构可定义构造函数,但不能定义析构函数。无参构造函数(默认)是自动定义的,且不能被改变。
- 与类不同,结构不能继承其他的结构或类。
- 结构不能作为其他结构或类的基础结构。
- 结构可实现一个或多个接口。
- 结构成员不能指定为 abstract、virtual 或 protected。
- 当您使用 New 操作符创建一个结构对象时,会调用适当的构造函数来创建结构。与类不同,结构体可以不使用 New 操作符即可被实例化。
- 如果不使用 New 操作符,只有在所有的字段都被初始化之后,字段才被赋值,对象才被使用。
- 结构体的字段无法赋初始值。
- 类和结构体的区别
类和结构有以下几个基本的不同点:
- class 是引用类型,struct 是值类型。
- struct 不支持继承。
- struct 是值类型,class 是对象类型
- struct 不能被继承,class 可以被继承
- struct 默认的访问权限是public,而class 默认的访问权限是private.
- struct 总是有默认的构造函数,即使是重载默认构造函数仍然会保留。这是因为struct的构造函数是由编译器自动生成的,但是如果重载构造函数,必需对struct中的变量全部初始化。并且struct的用途是那些描述轻量级的对象,例如Line,Point等,并且效率比较高。class在没有重载构造函数时有默认的无参数构造函数,但是一被重载,默认构造函数将被覆盖。
- struct的new和class的new是不同的。struct的new就是执行一下构造函数创建一个新实例再对所有的字段进行Copy。而class则是在堆上分配一块内存然后再执行构造函数,struct的内存并不是在new的时候分配的,而是在定义的时候分配。
在C#中,我们用struct/class来声明一个类型为值类型/引用类型。考虑下面的例子:
SomeType[] oneTypes = new SomeType[100];
- 如果SomeType是值类型,则只需要一次分配,大小为SomeType的100倍。
- 如果SomeType是引用类型,刚开始需要100次分配,分配后数组的各元素值为null,然后再初始化100个元素,结果总共需要进行101次分配。这将消耗更多的时间,造成更多的内存碎片。所以,如果类型的职责主要是存储数据,值类型比较合适。
频繁创建的消耗对比
如果在Update不停实例化一个类,会发生什么?如果在Update不停实例化一个结构体,会发生什么?
class:
就会不断申请堆内存,导致内存碎片不断增多,频繁触发GC,造成掉帧,发热等问题。
struct:
结构体是值类型,程序离开Update这个方法的时候,栈上为变量所分配的内存空间都会被清除。
- 带方法的结构体
using System;
using System.Text;
struct Books
{
private string title;
private string author;
private string subject;
private int book_id;
public void setValues(string t, string a, string s, int id)
{
title = t;
author = a;
subject = s;
book_id =id;
}
public void display()
{
Console.WriteLine("Title : {0}", title);
Console.WriteLine("Author : {0}", author);
Console.WriteLine("Subject : {0}", subject);
Console.WriteLine("Book_id :{0}", book_id);
}
};
public class testStructure
{
public static void Main(string[] args)
{
Books Book1 = new Books(); /* 声明 Book1,类型为 Books */
Books Book2 = new Books(); /* 声明 Book2,类型为 Books */
/* book 1 详述 */
Book1.setValues("C Programming",
"Nuha Ali", "C Programming Tutorial",6495407);
/* book 2 详述 */
Book2.setValues("Telecom Billing",
"Zara Ali", "Telecom Billing Tutorial", 6495700);
/* 打印 Book1 信息 */
Book1.display();
/* 打印 Book2 信息 */
Book2.display();
Console.ReadKey();
}
}
总结
通常情况下,枚举是最常用的,首先它是值类型,不会导致堆溢出,降低了程序运行风险。且枚举多数用于键值对应,在尽量少占用内存的情况下又能够充分解耦,是最值得使用的类型。
其次是同为值类型的结构体,也是可以使用的,但使用场景其实并不算多。
最后是索引器,一般只在类的属性需要声明为数组的时候使用,是否适用于Unity还有待商榷,毕竟涉及到动态类型,IOS端支持情况尚不确定。
以上是个人对于这三种语法的理解,如有不对的地方,欢迎大家给予指正。
本文部分内容引自:
https://www.cnblogs.com/kissdodog/archive/2013/01/16/2863515.html
https://www.cnblogs.com/promise-7/archive/2012/01/12/2320401.html
https://www.cnblogs.com/seanbrucexxl/p/3878760.html
https://www.runoob.com/csharp/csharp-struct.html
https://zhuanlan.zhihu.com/p/358825256
感谢分享~
更多内容请查看总目录【Unity】Unity学习笔记目录整理