在学习C#过程中,我经常有些知识点容易混淆,于是记录一下,主要是给自己看。我喜欢虚空捏造个“什么都不知道的”对象、然后以一种“教学”的口吻去分享知识,实际上只是方便自身记忆与学习而已,于是就以这种方式去记录。我本身是医学院的学生、肯定会有一些错误的地方,望批评指正。
个人学习是参考b站up“唐老狮”的"C#四部曲"进行的,以此做笔记给自己看。
值类型与引用类型的区别
很多小伙伴(虚空捏造对象)容易搞混值类型与引用类型的知识,如:
int a =2;
int b = a;
b = 3;
string c = "理理";
string d = "aurora"
d = "小理理"
上例子中,改变了b和d的值,那么a和c的值分别是什么?实际上,a还是2,c却变成“小理理”了。原因是string是引用类型,创建的数据存储在“堆”中,而Int是值类型存储在“栈”上。
类和结构体的区别
二者长相挺相似的,但却有很大不同。
1.结构体是以struct关键字开头的一种东西,是值类型、不能继承(虽然我还没学到继承就是了),类以class为关键字,存储在“堆”,是引用类型,可以继承。
2.结构体不能初始化变量,类却可以,如public int a = 5
,这句代码在结构体中是不行的,会直接报错;在类中却可以。
3.结构体不能申明无参的构造函数,类却可以,如public void Display()
在类中可以,结构体中就不行了,括号里必须传进参数
变量?参数?类的实例
变量和参数是不同的,参数一般是我们从外部要传进来的东西,举个例子,
public class Program
{
// 这是一个变量
public static int myVariable = 10;
public static void Main(string[] args)
{
// 这是一个参数
MyFunction(5);
}
public static void MyFunction(int myParameter)
{
// 参数在函数内部被使用
Console.WriteLine("参数的值: " + myParameter);
}
}
在调用上边代码时,MyFunction(5),myParameter是我们要传进来的参数,我们起个名字而已,用于代表、示例作用。变量通常用于存储数据用,如myVariable = 10;
类的示例就是另外一回事,她是某一类的具体化,如
class Person
{
private string name;
private int age;
private Person[] friends;
}
Person p = new Person()
p是我们Person类中具体化的一个对象,我们创造出一个名为p的、Person类的东西,我们很多操作都是基于这个对象来进行的,如p.name = "理理";
还有容易搞混的是,我以前傻傻分不清上边代码的,Person[] 和friends[];friends是我们
创造的一个实例,只不过它是数组形式的示例,friends这个数组里只能存储Person类的东西。
类、结构、方法、属性
很多人傻傻分不清,于是举例子。
namespace practice
{
class Family
{
//这里的age 和 name是我们的私有变量
int age;
string name;
//这里的age1 和 name1是我们外部传的参数,我们自定义个构造器
public Family(int age1, string name1)
{
age = age1;
name = name1;
}
public void Speak()
{
Console.WriteLine($"我叫{name},我今年{age}岁了");
}
}
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello, World!");
Family xiaoming = new Family(5, "小明");
xiaoming.Speak();
Console.ReadLine();
}
}
}
这里我们定义一个family类,类中有个构造器:public Family(int age1, string name1)
,在类中,我们可以这样定义默认构造器:public Family()
,在构造器里写一堆东西,但是在结构体中这语法是不行的,结构体不允许我们自定义无参数的默认构造器,也就是括号里必须填进去东西。
关于属性:
public class Person
{
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
}
属性是用来修饰私有字段的东西,如我定义一个名为“Name”的属性,里边封装的是我们的私有变量name;属性有什么用?属性加上“public”或者“private”修饰符,可以用来控制我们的私有字段,保证安全性。比如我们把set设置为private、get设置为public,这样在Main方法中,这个私有字段变为“只读状态”,只能读不能修改。再举个形象的例子,你是公司程序员、设置主角血量100,结果某天被裁了(不好笑的笑话),新来的糊涂蛋程序员要捣鼓血量这东西,有了以上的方法,新来的程序员再后来写代码时犯浑、就不能在Main方法中通过“blood = 200”把血量改成200,从而保障数据安全性。
关于方法
方法就是程序执行的步骤,要求程序要怎样去做一件事,常规格式:public(可选,看看需不需要public) static(可选,一会儿讲其作用) 返回值类型(没有返回值就填void) 函数名(传的参数类型 参数),如 public static void Speak(string name)
,那么static有什么用?
static通常用来修饰用于修饰类成员,如
public class Utility
{
public static int Counter; // 静态字段
static Utility() // 静态构造函数
{
Counter = 0;
}
public static void Increment() // 静态方法
{
Counter++;
}
public static int GetCounter // 静态属性
{
get { return Counter; }
}
}
class Program
{
static void Main(string[] args)
{
Utility.Increment(); // 调用静态方法
Console.WriteLine(Utility.GetCounter); // 访问静态属性
}
}
它的作用就是不用创造实例、直接调用方法,如Mathf类的Mathf.Abs
,用来直接计算绝对值的。以往我们用类的时候,都要创造个实例、再调用方法,这就太麻烦了。于是有了static,我们连实例都不用创造、直接调用方法,十分方便。
索引器
之前一直思考,索引器有什么用?貌似索引器能实现的东西、用数组也能,然后把自己绕迷了。关于索引器的讲解推荐看b站某视频,不推荐看唐老狮将C#核心中的那期索引器(容易绕进去)。索引器是个“语法糖”,也就是这种语法是非必要的、不学它也能实现它的功能,只不过方便就是了。明白这点就比较容易搞清楚了。
//定义一个 Name 属性来操作 name 字段
public string Name
{
set { name = value; }
get { return name; }
}
//定义一个 Password 属性来操作 password 字段
public string Password
{
set { password = value; }
get { return password; }
}
//定义索引器,name 字段的索引值为 0 ,password 字段的索引值为 1
public string this[int index]
{
get
{
if (index == 0) return name;
else if (index == 1) return password;
else return null;
}
set
{
if (index == 0) name = value;
else if (index == 1) password = value;
}
}
}
//使用索引器的方式来给类的两个属性赋值
p[0] = "jarod";
p[1] = "123456,./";
//使用类属性取得两个字段信息
Label1.Text = p.Name + " / " + p.Password;
}
静态成员
静态是说,对于一个类、不需要实例化对象,能直接调用里边的变量、方法等,举个例子:
namespace ConsoleApp2
{
class Test
{
static float PI = 3.1415926f;
public const float H = 1.23f;
public static float Circle(float r)
{
return PI * r * r;
}
}
internal class Program
{
static void Main(string[] args)
{
float a = Test.Circle(2);
Console.WriteLine(a);
Console.ReadLine();
}
}
}
圆的面积计算很常见,有了静态后,我们不用再先 TestCircle a = new Circle()
之类的,先实例化对象再用方法了,可以直接通过“类名.方法”来调用,很方便,程序运行时会自动给静态成员先分配个空间。const是常量,算是种特殊的静态,要求必须初始化赋值、而且访问修饰符在const前(static就没这要求),而且一旦赋值就不能修改。
静态虽然好用,但不能一直用、甚至全用静态,因为在垃圾回收时,静态成员是不会被回收掉的,一直用静态容易爆内存。静态能修饰的东西很多,主要是方便吧
运算符重载
标准格式大概:public static 返回值类型 operator 运算符(两个参数),在Unity中感觉可以用来做向量的加减,写角色控制器。
class XL
{
public int x;
public int y;
public int z;
public XL(int x, int y, int z)
{
this.x = x;
this.y = y;
this.z = z;
}
public static XL operator +(XL x, XL y)
{
return new XL(x.x + y.x, x.y + y.y, x.z + y.z);
}
public static XL operator -(XL x, XL y)
{
return new XL(x.x - y.x, x.y - y.y, x.z - y.z);
}
}