C#核心

导航

请根据右侧目录进行自助跳转

类名

{

(写在类中的)

成员变量

成员方法

初始化调用-构造函数

释放时调用-析构函数

成员属性

索引器

静态成员-类名点出使用

运算符重载

}

(写在类外的)

静态类和静态构造函数

拓展方法

类和对象

什么是类

基本概念:

  1. 具有相同特征
  2. 具有相同行为
  3. 一类事物的抽象
  4. 类是对象的模板
  5. 可以通过类创建出对象
  6. 类的关键词:class

类声明在哪里

一般声明在namespace的语句块中

类声明的语法

1
2
3
4
5
6
7
8
9
10
访问修饰符(pubic,private) class 类名
{
//成员变量--特征
//成员方法--行为
//成员属性--保护特征
//构造函数和析构函数
//索引器
//运算符重载
//静态成员
}

类声明实例

1
2
3
4
5
6
7
8
9
10
11
12
13
//这个类是用来形容人类的
//注意命名:用帕斯卡命名法
//同一个语句块中的不同类 不能重名
class Person
{
//成员变量--特征
//成员方法--行为
//成员属性--保护特征
//构造函数和析构函数
//索引器
//运算符重载
//静态成员
}

什么是(类)对象

基本概念:

  1. 类的声明类对象(变量)声明两个概念
  2. 类的声明类似枚举结构体的声明,类的声明相当于声明了一个自定义的变量类型
  3. 而对象是类创建出来的
  4. 相当于声明一个指定类的变量
  5. 类创建对象的过程一般称为实例化对象
  6. 类对象都是引用类型的(数组 string都是引用类型 而 结构体是值类型)

实例化对象的基本语法

1
2
3
//类名 变量名;					 //默认为空
//类名 变量名 = null;(null代表空) //默认为空
//类名 变量名 = new 类名(); //初始化

实例化对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
using System;
class Person
{
}
class Program
{
static void Main(string[] args)
{
Person p;
Person p2 = null;//null 代表空 不分配堆内存空间
Person p3 = new person();//一个人的对象
Person p4 = new person();//另一个人的对象
//虽然是来自一个类的实例化对象
//但是他们的特征 行为等信息都是他们所独有的
//千万千万不要觉得他们是共享了数据两个人 你是你 我是我 彼此没有关系
}
}

练习题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
using System;
class GameObject
{
}
class Program
{
static void Main(string[] args)
{
GameObject A = new GameObject();
GameObject B=A;
B= null;
//A目前等于多少
GameObject A = new GameObject();
GameObject B=A;
B= new GameObject();
//A和B有什么关系
}
}

答案

1.因为类是一个引用类型,所以B=A实际上是在栈中创建了两个不同的空间,但是二者的地址相同因此所指向堆中的空间也相同。但是B=NULL,是将栈中的B所占有的空间替换为空,从而没有影响到堆中的空间。因此A不受影响,等于原来的值

2.和上题一样,都是在栈中创建了两个不同的空间,一开始令B=A使B与A都指向了堆中相同的空间,但后来B= new GameObject();使B在堆中又创立了一个不同的空间,因此在堆中指向的空间也不同。所以A与B没有关系

成员变量和访问修饰符

成员变量

  1. 基本规则:
  2. 声明在类语句块中
  3. 用来描述对象的特征
  4. 可以是任意变量类型
  5. 数量不做限制
  6. 是否赋值根据需求来定
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
enum E_SexType
{
Man,
Woman,
}
struct Position
{

}
class pet
{

}
class Person
{
//成员变量--特征
//姓名
string name = '铅笔沫';
//年龄
int age;
//性别
E_SexType sex;
//女朋友
Person grilFriend;
//朋友
Person[] boyFriend;
//位置
Postion pos;
//宠物
Pet pet;
}

访问修饰符

public—公共的

private—私有的

protected—保护的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
using System;
enum E_SexType
{
Man,
Woman,
}
struct Position
{

}
class pet
{

}
class Person
{
//成员变量--特征
//姓名
public string name = '铅笔沫';
//年龄
public int age;
//性别
public E_SexType sex;
//女朋友
//如果要在类中声明一个和自己相同类型的成员变量时
//不能对它进行实例化
public Person grilFriend;
//朋友
public Person[] boyFriend;
//位置
public Postion pos;
//宠物
public Pet pet;
}
class Program
{
static void Main(string[] args)
{
Person p = new Person();
}
}

成员变量的使用和初始值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Program
{
static void Main(string[] args)
{
Person p = new Person();
//值类型 默认值是0
//boll类型 默认值是false
//引用类型 默认值是NULL
//看默认值的小技巧 default(变量名称)
Console.WriteLine(default(bool));//false
Console.WriteLine(default(int)); //0
Console.WriteLine(default(Person)); //打印出来看不到因为是空
p.age = 10;
Console,WriteLine(p.age); //10
}
}

练习题

Q1:3p是什么

Q2:定义一个人类

Q3:定义一个学生类(带有同桌)

Q4:定义一个班级类(专业名称,教师容量,学生)

Q5:请问p.age为多少

1
2
3
4
Person p = new Person();
p.age = 10;
Person p2 = new Person();
p2.age = 20;

Q6:请问p.age为多少

1
2
3
4
Person p = new Person();
p.age = 10;
Person p2 = p;
p2.age = 20;

Q7:请问s.age为多少

1
2
3
4
Student s = new Student();
s,age = 10;
int age = s.age;
age = 20;

Q8:请问s.deskmate.age为多少

1
2
3
4
5
Student s = new Student();
s.deskmate = new Student();
s.deskmate.age = 10;
Student s2 = s.deskmate;
s2.age = 20;

答案

A1:

private,public,protected

A2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Person
{
public string name;
public int age;
public string homeAddress;
}
class Program
{
static void Main(string[] args)
{
Person p = new Person();
p.age = 18;
p.name ='铅笔沫';
p.homeAddress = '佳木斯'
//etc
}
}

A3:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Student
{
public string name;
public int age;
public string homeAddress;
public Student deskMate;
}
class Program
{
static void Main(string[] args)
{
Student p = new Student();
p.age = 18;
p.name ='铅笔沫';
p.homeAddress = '佳木斯'
Student p2 = new Student();
p2.age = 18;
p2.name ='云笙繁华';
p2.homeAddress = '佳木斯'
p.deskMate = p2;
p2.deskMate = p;
}
}

A4:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class CLass()
{
public string name;
public int capacity;
public Student[] students;
}
class Student
{
public string name;
public int age;
public string homeAddress;
public Student deskMate;
}
class Program
{
static void Main(string[] args)
{
Student p = new Student();
p.age = 18;
p.name ='铅笔沫';
p.homeAddress = '佳木斯'
Student p2 = new Student();
p2.age = 18;
p2.name ='云笙繁华';
p2.homeAddress = '佳木斯'
p.deskMate = p2;
p2.deskMate = p;
Class c = new Class();
c.name = "Unity";
c.capacity = 99999;
c.student = new student[] {p,p2};
}
}

A5:

10

A6:

二者指向地址相同,因此 p2,age = 20 与 p.age =20一致,因此p,age=20

A7:

因为age是一个值类型,没有通过地址改变s,age的值所以s,age 仍然等于10

A8:

因为Student s2 = s.deskmate 指向的同一个地址因此s2.age = 20 等价于 s.deskmate.age = 20

成员方法

成员方法的声明

基本概念:

  1. 成员方法(函数)用来表现对象的行为
  2. 声明在类语句块中
  3. 适应来描述对象的行为
  4. 规则和函数声明规则相同
  5. 受到访问修饰符的规则影响
  6. 返回值函数不做限制

注意:

  1. 成员方法不要加static关键字
  2. 成员方法 必须实例化出对象 再通过对象来使用 相当于该对象执行了某个行为
  3. 成员方法 收到访问修饰符的影响
1
2
3
4
5
6
7
8
9
10
11
12
13
class Person
{
public string name;
public int age;
public void Speak(string str)
{
Console.WriteLine("{0}说{1},"name.str);
}
public bool IsAdult()
{
return age >= 18;
}
}

成员方法的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
class Person
{
public string name;
public int age;
public Person[] friends;
public void Speak(string str)
{
Console.WriteLine("{0}说{1},"name.str);
}
public bool IsAdult()
{
return age >= 18;
}
public AddFriend(Person p)
{
if(friends == NULL)
{
friends = new Person[] {p};
}
else
{
//扩容 创建一个房子数组
Person[] newFriends = New Person[friends.Length + 1];
//搬家
for(int i =0;i<friends.Length;i++)
{
newFriends[i]=friends[i];
}
//把新加的朋友放到最后一个
newFriends[newFriends.Length-1]=p;
//地址重定向
friends = Newfriends;
}
}
}
class Program
{
static void Main(string[] args)
{
//成员方法 必须实例化出对象 再通过对象来使用 相当于该对象执行了某个行为
Person p = new Person();
p.name = "铅笔沫";
p.age =18;
p.Speak("你好呀");
p.IsAdult();
Person p2 = new Person();
p2.name = "云笙繁华";
p2.age =18;
P.AddFrind(p2);
for(int i=0; i<p.friends.Length;i++)
{
Console.WriteLine(p.Friends[i],name);//打印出朋友的名字
}
}
}

练习题

Q1:为人类定义说话,吃饭,走路等方法

Q2:定义一个食物类,有名称,热量等特征,并将其与人类和学生类联系起来

答案

A1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
using System;

namespace Homework
{
class People
{
public string name;
public int age;
public float height;
public string homeAddress;

public void Speak(string str)
{
Console.WriteLine("{0}说{1}", name, str);
}

public void Walk()
{
Console.WriteLine("{0}开始走路了", name);
}

public void Eat()
{
Console.WriteLine("{0}开始吃饭了", name);
}
}
class Program
{
static void Main(string[] args)
{
People p = new People();
p.name = "1111";
p.Speak("222222");
p.Walk();
p.Eat();
}
}
}

A3:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
using System;

namespace Homework
{
class food
{
public string name;
public int kaluli;
}
class People
{
public string name;
public int age;
public float height;
public string homeAddress;

public void Speak(string str)
{
Console.WriteLine("{0}说{1}", name, str);
}
public void Walk()
{
Console.WriteLine("{0}开始走路了", name);
}
public void Eat(food f)
{
Console.WriteLine("{0}开始吃{1}", name,f.name);
}
}
class Student
{
public string name;
public int age;
public float height;
public string homeAddress;

public void Learn()
{
Console.WriteLine("{0}在学习", name);
}

public void Eat(food f)
{
Console.WriteLine("{0}开始吃{1}", name,f.name);
}
}
class Program
{
static void Main(string[] args)
{
People p = new People();
p.name = "1111";
Student s = new Student();
s.name = "abcd";
food f = new food();
f.name = "3333";

p.Eat(f);
s.Eat(f);
}
}
}

构造函数和析构函数

构造函数

基本概念:

  1. 在实例化对象时 会调用的用于初始化的函数
  2. 如果不写默认存在一个无参构造函数

构造函数的写法

  1. 没有返回值
  2. 函数名和类名必须相同
  3. 没有特殊需求是 一般都是public的
  4. 构造函数可以被重载
  5. this代表当前调用该函数的对象自己

注意:

如果声明了有参构造而没有声明无参构造,则不能使用无参构造去实例化对象

参考C++

this.的用法

1
2
3
4
5
6
7
8
class Person
{
public Person(int age)
{
//this代表当前调用的该函数的对象的自己
this.age = age;
}
}

构造函数的特殊写法

可以通过this 重用构造函数代码

访问修饰符 构造函数名(参数列表):this(参数1,参数2…..)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Person
{
public Person()
{
name = "云笙繁华";
age = 18;
}
public Person(int age,string name):this()
{
Console.WriteLine("两个参数构造函数调用");
}
}
class Program
{
static void Main(string[] args)
{
Person p = new Person(18,"铅笔沫");
Console.WriteLine(p.age);
}
}

使用这种特殊写法,会先调用this()(无则无参,有则对应到this里对应内容的函数),之后再调用该函数中的内容,并且this中的内容可以写死,或者进行默认的增减调整,会自动根据类型转到对应的函数

析构函数

基本概念:

  1. 当引用类型的堆内存被回收时,会调用该函数
  2. 对于需要手动管理内存的语言(比如C++),需要在析构函数中做一些内存回收处理
  3. 但是C#中存在自动垃圾回收机制GC
  4. 所以我们几乎不会怎么使用析构函数,除非你想在某一个对象被垃圾回收时,做一些特殊处理
  5. 在垃圾真正被回收的时候,才会调用的函数

注意:

在Unity开发中析构函数几乎不会使用

基本语法:

1
2
3
~类名()
{
}

垃圾回收机制

垃圾回收,英文简写GC(Garbage Collector)

垃圾回收的过程是在遍历堆(Heap)上动态分配的所有对象

通过识别它们是否被引用来确定哪些对象是垃圾,哪些对象仍要被引用

所谓的垃圾就是没有被任何变量,对象引用的内容

垃圾就需要被回收释放

垃圾回收有很多种算法,比如

引用计数(Reference Counting)

标记清楚(Mark Sweep)

标记整理(Mark Compact)

复制整合(Copy Collection)

注意:

GC只负责堆(Heap)内存的垃圾回收

引用类型都是存在堆(Heap)中的,所以它的分配和释放都通过垃圾回收机制来管理

栈(Stack)上的内存是由系统自动管理的

值类型在栈(Stack)中分配内存的,他们有自己的生命周期,不用对他们进行管理,会自动分配和释放

C#中内存回收机制的大概原理

0代内存 1代内存 2代内存

代的概念:

代是垃圾回收机制使用的一种算法(分代算法)

新分配的对象都会被配置在第0代内存中

每次分配都可能会进行垃圾回收以释放内存(0代内存满时)

在一次内存回收过程开始时,垃圾回收器会认为堆中全是垃圾,会进行以下两步

1.标记对象从根(静态字段、方法参数)开始检查引用对象,标记后为可达对象,未标记为不可达对象//不可达对象就认为是垃圾

2.搬迁对象压缩堆―(挂起执行托管代码线程)释放未标记的对象搬迁可达对象修改引用地址

大对象总被认为是第二代内存目的是减少性能损耗,提高性能

不会对大对象进行搬迁压缩8500o字节(83kb)以上的对象为大对象

简而言之,0代内存满时,触发GC将不可达对象清除,将可达对象转移至1代内存,当1代内存满时,再次触发GC,将可达对象转移至2代内存,并且将0、1代内存同时清空。

手动触发GC

1
GC.collect();

一般情况下 我们不会频繁调用

都是在 Loading过场景时 才调用

练习题

Q1:基于成员方法,对人类的构造函数进行重载,用人类创建若干个对象

Q2:基于成员变量,对班级类的构造函数进行重载,用班级类创建若干个对象

Q3:写一个Ticket类

写一个Ticket类,有一个距离变量(在构造对象时赋值,不能为负数),有一个价格特征,有一个方法GetPrice可以读取到价格,并且根据距离distance计算价格price ( 1元/公里)

0~100公里不打折

101~200公里打9.5折

201~300公里打9折

300公里以上打8折

有一个显示方法,可以显示这张票的信息。

例如:100公里100块钱

答案

A1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
using System;

namespace Homework
{
class Food
{
public string name;
public int kaluli;
}
class People
{
public string name;
public int age;
public float height;
public string homeAddress;

public void Speak(string str)
{
Console.WriteLine("{0}说{1}", name, str);
}
public void Walk()
{
Console.WriteLine("{0}开始走路了", name);
}
public void Eat(Food f)
{
Console.WriteLine("{0}开始吃{1}", name,f.name);
}
public People(string name,float height,int age,string homeAddress) :this(name,height)
{
this.age = age;
this.homeAddress = homeAddress;
}
public People(string name,float height)
{
this.name = name;
this.height = height;
}

}
class Program
{
static void Main(string[] args)
{
People p1 = new People("铅笔沫", 177, 19, "佳木斯");
People p2 = new People("云",165, 18, "佳木斯");
}
}
}

A2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
using System;

namespace Homework
{
class Food
{
public string name;
public int kaluli;
}

class Class
{
public string name;
public int capacity;
public Student[] students;

public Class(string name,int capacity)
{
this.name = name;
this.capacity = capacity;
}

public Class(string name,int capacity ,Student[] students):this(name,capacity)
{
this.students = students;
}
}
class Student
{
public string name;
public int age;
public float height;
public string homeAddress;

public void Learn()
{
Console.WriteLine("{0}在学习", name);
}

public void Eat(Food f)
{
Console.WriteLine("{0}开始吃{1}", name, f.name);
}
}
class People
{
public string name;
public int age;
public float height;
public string homeAddress;

public void Speak(string str)
{
Console.WriteLine("{0}说{1}", name, str);
}
public void Walk()
{
Console.WriteLine("{0}开始走路了", name);
}
public void Eat(Food f)
{
Console.WriteLine("{0}开始吃{1}", name,f.name);
}
public People(string name,float height,int age,string homeAddress) :this(name,height)
{
this.age = age;
this.homeAddress = homeAddress;
}
public People(string name,float height)
{
this.name = name;
this.height = height;
}

}
class Program
{
static void Main(string[] args)
{
People p1 = new People("铅笔沫", 177, 19, "佳木斯");
People p2 = new People("云",165, 18, "佳木斯");
Class c1 = new Class("Unity", 999999);
Student s1 = new Student();
Student s2 = new Student();
Class c2 = new Class("C#", 999999,new Student[] {new Student(),new Student()});
}
}
}

A3:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
using System;

namespace Homework
{
class Food
{
public string name;
public int kaluli;
}
class Class
{
public string name;
public int capacity;
public Student[] students;

public Class(string name,int capacity)
{
this.name = name;
this.capacity = capacity;
}

public Class(string name,int capacity ,Student[] students):this(name,capacity)
{
this.students = students;
}
}
class Student
{
public string name;
public int age;
public float height;
public string homeAddress;

public void Learn()
{
Console.WriteLine("{0}在学习", name);
}

public void Eat(Food f)
{
Console.WriteLine("{0}开始吃{1}", name, f.name);
}
}
class People
{
public string name;
public int age;
public float height;
public string homeAddress;

public void Speak(string str)
{
Console.WriteLine("{0}说{1}", name, str);
}
public void Walk()
{
Console.WriteLine("{0}开始走路了", name);
}
public void Eat(Food f)
{
Console.WriteLine("{0}开始吃{1}", name,f.name);
}
public People(string name,float height,int age,string homeAddress) :this(name,height)
{
this.age = age;
this.homeAddress = homeAddress;
}
public People(string name,float height)
{
this.name = name;
this.height = height;
}


}
class Ticket
{
public uint distance;
public float price;
public Ticket(uint distance)
{
this.distance = distance;
price = GetPrice();
}
private float GetPrice()
{
if(distance >300)
{
return distance * 0.8f;
}
else if(distance>=201&&distance<=300)
{
return distance * 0.9f;
}
else if(distance>=101&&distance<=200)
{
return distance * 0.95f;
}
else
{
return distance;
}
}
public void ShowInfo()
{
Console.WriteLine("{0}公里{1}块钱",distance,price);
}
}
class Program
{
static void Main(string[] args)
{
People p1 = new People("铅笔沫", 177, 19, "佳木斯");
People p2 = new People("云",165, 18, "佳木斯");
Class c1 = new Class("Unity", 999999);
Student s1 = new Student();
Student s2 = new Student();
Class c2 = new Class("C#", 999999,new Student[] {new Student(),new Student()});
}
}
}

成员属性

基本概念

与c++类似

public—公共

private—私有

protected—保护

基本语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
//访问修饰符 属性类型 属性名
//{
// get{}//要有返回值
// set{}
//}
class Person
{
private string name;
private int age;
private int money;
public string Name
{
get
{
//解密处理
//可以在返回之前添加一些逻辑规则
//意味这个属性可以获取的内容
return name;
}
set
{
//可以进行加密处理
//可以在设置之前添加一些逻辑规则
//value 关键字 用于表示外部传入的值
name = value;
}
}
public int Money
{
get
{
//解密
return monet-5;
}
set
{
//加密
money=value+5;
}
}
}

使用方法

1
2
3
4
5
6
7
8
9
10
class Progarm
{
static void Main(string[] args)
{
Console.WriteLine("成员属性");
Person p = newPerson();
p.Name = "qianbimo";//执行set
Console.WriteLine(p.name);//执行get
}
}

访问修饰符

PS:

1.默认不加 会使用属性中声明的访问权限

2.加的访问修饰符要低于属性的访问权限

3.不能让get和set的访问权限都低于属性的权限

Public>Private>Protected

可以解决3P的局限性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public int Money
{
get
{
return money - 5;
}
set
{
money = value + 5;
}
/*
private get
{
return money - 5;
}
private set //报错
{
money = value +5;
}
*/
}

get 和 set 可以只有一个

意思是,在一个成员中 可以只有get或set其中一个。

一般用在 只希望得到数据 但是不希望让他人获得数据的时候

而且因为只有一个 get 或者 set 所以完全不需要在前面加上访问修饰符。

其实说人话,就是在于,只读与只写的不同罢了。

1
2
3
4
5
6
7
pubilc bool Sex
{
get
{
return sex;
}
}

自动属性

作用就在于,外部能得但是不能改的特征

如果类中有一个特征是只希望外部能得不能改的,又没什么特殊处理

那么可以直接使用自动属性

1
2
3
4
5
6
public float Height
{
//没有在get 和 set 中写逻辑需求的想法
get;
set;
}

在这里 会自动设定一个 变量 将获取到的值蕴含在里面

练习题

Q1:

定义一个学生类,有五种属性,分别为姓名,性别,年龄,Csharp成绩,Unity 成绩

有两个方法:

一个打招呼,介绍自己叫xxx,今年几岁了,性别是什么,计算自己的总分数和平均分并显示的方法

使用属性完成:年龄必须是0~150 岁之间,成绩必须是 0~100

性别只能是男女

实例化两个对象并测试。

A1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
using System;
using System.Runtime.InteropServices;

namespace Homework
{
class Student
{
private int age;
private int csharp;
private int unity;
private string sex;
public string Name
{
get;
set;
}
public string Sex
{
get
{
return sex;
}
set
{
if(value !="男"&&value!="女")
{
sex = "不男不女";
}
else
{
sex = value;
}
}
}
public int Age
{
get
{
return age;
}
set
{
if (value < 0)
{
age = 0;
}
else if (value > 150)
{
age = 150;
}
else
{
age = value;
}
}
}
public int Csharp
{
get
{
return csharp;
}
set
{
if (value < 0)
{
csharp = 0;
}
else if (value > 100)
{
csharp = 100;
}
else
{
csharp = value;
}
}
}
public int Unity
{
get
{
return unity;
}
set
{
if (value < 0)
{
unity = 0;
}
else if (value > 100)
{
unity = 100;
}
else
{
unity = value;
}
}
}
public void SayHello()
{
Console.WriteLine("我叫{0},今年{1}岁了,是{2}同学",Name,Age,Sex);
}
public void ShowInfo()
{
int sum = Csharp+Unity;
float avg = sum / 2f;
Console.WriteLine("总分{0},平均分{1}", sum, avg);
}
}
class Program
{
static void Main(string[] args)
{
Student s1 =new Student();
s1.Name = "铅笔沫";
s1.Age = 114514;
s1.Unity = 1919810;
s1.Csharp = 1545454;
s1.Sex = "男";
s1.SayHello();
s1.ShowInfo();

Student s2 =new Student();
s2.Name = "云笙繁华";
s2.Age = 18;
s2.Unity = -100;
s2.Csharp = 100;
s2.Sex = "女";
s2.SayHello();
s2.ShowInfo();
}
}
}

索引器

基本概念

让对象可以像数组一样通过索引访问其中的元素,使程序看起来更直观,更容易编写

基本语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
访问修饰符 返回值 this[参数类型 参数名,参数类型 参数名.....]
{
内部的写法和规则和索引器相同
get{};
set{};
}
class Person
{
private string name;
private int age;
private Person[] friends;

public Person this[int index]
{
get
{
return friends[index];
}
set
{
//value代表传入的值
friends[index] = value;
}
}
}

使用方法

1
2
3
4
5
6
7
8
9
10
class Program
{
static void Main(string[]args)
{
Console.WriteLine("索引器");
Person P = new Person();
p[0] = new Person();
Console.WriteLine(p[0]);
}
}

索引器中可以写逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public Person this[int index]
{
get
{
//可以写逻辑的 根据需求来处理这里面的内容
if(friends == null || friends.Length - 1<index)
{
return null;
}//解决月结报错
}
set
{
if(friends == null)
{
friends = new Person[]{value};
}
friends[index] = value;
}
}

索引器可以重载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
class Person
{
private string name;
private int age;
private Person[] friends;
private int[,] array;

//索引器的重载
public int this[int i,int j]
{
get
{
return array[i,j];
}
set
{
array[i,j]=value;
}
}
public int this[string str]
{
get
{
switch(str)
{
case "name":
return this.name;
case "age":
return age.ToString();
}
return "";
}
}
public Person this[int index]
{
get
{
return friends[index];
}
set
{
//value代表传入的值
friends[index] = value;
}
}
}
class Program
{
static void Main(string[]args)
{
Console.WriteLine("索引器");
Person P = new Person();
p[0] = new Person();
Console.WriteLine(p[0]);

p[0,0] =10;
}
}

练习题

Q1:

自定义一个整型数组类,该类中有一个整型数组变量为它封装增删查改的办法

静态成员

基本概念

静态关键字 static

用 static 修饰的 成员变量、方法、属性等

特点 类名.变量名称就是静态变量

自定义静态成员

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Test
{
//静态成员变量
public static float PI = 3.1415926;
//成员变量
public int TestInt = 100;

public static float CalcCircle(float r)
{
return PI * r * r;
}
public void TestFun()
{
Console.WriteLine("123");
}
}

使用方法

1
2
3
4
5
6
7
8
9
10
11
class Program
{
static void Main(string[] args)
{
Console.WriteLine(Test.PI);
Console.WriteLine(Test.CalcCricle(2));
Test t = new Test();
Console.WriteLine(t.testInt);
t.Testfun();
}
}

为什么静态变量可以直接进行使用

众所周知,程序不能无中生有,实例化对象的目的就是为对象等进行分配空间。那为什么静态变量就可以直接使用呢?

静态成员的特点:

静态变量有一个属于自己的大空间叫做静态存储区

1.程序开始运行时 就会分配内存空间,所以就可以直接使用

2.静态成员和程序同生共死

3.只有使用静态变量,程序结束时内存空间才会释放,所以一个静态成员就会有自己唯一的一个”内存小房间”,这就让静态成员有了自己的唯一性

4.在任何地方使用都是用小房间的内容,改变的也是房间内的内容。

静态函数中不能使用非静态成员

成员变量只能将对象实例化出来后 才能点出来使用 不能无中生有

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Test
{
//静态成员变量
public static float PI = 3.1415926;
//成员变量
public int TestInt = 100;

public static float CalcCircle(float r)
{
return PI * r * r;
//下行会进行报错
//Console.WriteLine(testInt);
//如果想要使用的话 必须先实例化对象后才能使用
//如下
Test t = new Test();
Console.WriteLine(t.testInt);
}
public void TestFun()
{
Console.WriteLine("123");
}
}

非静态函数可以使用静态成员

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Test
{
public static float PI = 3.1415926;

public int TestInt = 100;

public static float CalcCircle(float r)
{
return PI * r * r;
}
public void TestFun()
{
Console.WriteLine("123");
Console.WriteLine(PI);
Console.WriteLine(CalcCricle);
}
}

常量和静态变量

const(常量)可以理解为特殊的static(静态)

相同点:

都可以通过类名.

不同点:

1.const必须初始化不能修改,static没有这种限制

2.const只能修饰变量,static可以修修很多

3.const一定是卸载访问修饰符后面的,static没有这个要求

练习题

Q1:

请说出const与static的区别

Q2:

请用静态成员来实现

一个类对象在整个应用程的生命周期中,有且仅会有一个该对象不存在,不能再外部实例化,直接通过该类类名就能得到唯一的对象

静态类和构造函数

静态类

基本概念

用static修饰的类

特点

只能包含静态成员,不能被实例化 更适合被当作工具类

作用

1.将常用的静态成员写在静态类中 方便使用

2.静态类不能被实例化,更能体现工具类的 唯一性

比如 Console就是一个静态类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
using System;
namespace std
{
static class value
{
// public int value
//报错 因为只能声明静态成员变量
public static int testIndex =0;
public static void TestFun()
{

}
public static int TestIndex
{
get;
set;
}
}
class Program
{
static void Main(string[] args)
{
Console.WhiteLine(”铅笔沫“);
}
}
}

静态构造函数

基本概念

在构造函数之前加上 static 修饰

特点

1.静态类和普通类都可以有

2.不能使用访问修饰符

3.不能有参数

4.只会自动调用一次

作用

在静态构造函数中初始化 静态变量

使用

静态类中的静态构造函数

1
2
3
4
5
6
7
8
9
static class StaticClass
{
public static int testInt = 100;
public static int testInt2 = 100;
static StaticClass
{
Console.WhiteLine("调用静态构造函数");
}
}

调用顺序

在第一次使用静态类时,就会自动调用一次静态构造函数

普通类中的静态构造函数

1
2
3
4
5
6
7
8
9
10
11
12
class Test
{
public static int testInt =200;
static Test()
{
Console.WriteLine("静态构造");
}
public Test()
{
Console.WriteLine("普通构造");
}
}

调用顺序

在第一次使用普通类时,就会自动优先调用一次静态构造函数

练习题

Q1:

写一个用于数学计算的静态类

对类中提供计算圆面积,圆周长,矩形面积,矩形周长,取个数的绝对值方法等

拓展方法

基本概念

为现有的非静态 变脸类型 添加 新方法

作用

1.提升程序的拓展性

2.不需要在对象中重新写方法

3.不需要继承来添加方法

4.为别人封装的类型写额外的方法

特点

1.一定写在静态类当中的

2.一定是个静态函数

3.第一个参数为拓展目标

4.第一个参数用this修饰

基本语法及其使用

3P访问修饰符 static 返回值 函数名(this 拓展类名 参数名,参数类型 参数名,参数类型 参数名........)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
using System;
namespace std;
{
static class Tools
{
//为int拓展了一个成员方法
//成员方法是需要 实例化对象才能使用的
//value 代表使用该方法的实例化对象
//没有参数的
public static void SpeakValue(this int value)
{
//拓展方法的逻辑
Console.WriteLine("int的拓展方法"+value);
}
//带参数的
public static void SpeakStringInfo(this string str, string str2,string str3)
{
Console.WriteLine("string的拓展方法");
Console.WriteLine("调用的对象"+str);
Console.WriteLine("传的参数"+str2+str3);
}
}
class Program
{
static void Main(string[] args)
{
int i = 10;
//使用方法
i.SpeakValue();
string str = "000";
str.SpeakStringInfo("111","222");
}
}
}

自定义类型的拓展方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
using System;
namespace std;
{
class Test
{
public i =10;
public void Fun1()
{
Console.WriteLine("123");
}
public void Fun2()
{
Console,WriteLine("456");
}
}
public static void Fun3 (this Test t)
{
Console.WhiteLine("为test拓展的方法");
}
class Program
{
static void Main(string[] args)
{
Test t = new Test();
t,Fun3();
}
}
}

注意:如果新加入的方法和原有的方法重名,则会优先调用原有的方法!

练习题

Q1:

为整形拓展一个求平方的方法

Q2:

写一个玩家类,包含姓名,血量,攻击力,防御力等特征,攻击,移动,受伤等方法
为玩家类拓展一个自杀的方法

运算符重载operator

基本概念

让自定义的类与结构体,能够使用运算符

特点

  1. 一定是一个公共的静态方法
  2. 返回值写在operator之前
  3. 逻辑处理自定义
  4. 返回值自定义

注意

  1. 条件运算符需要成对实现
  2. 一个符号可以多个重载
  3. 不能使用refout

基本语法

public static 返回类型 operator 运算符(参数列表)

实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Point
{
public int x;
public int y;

public static Point operator +(Point p1,Point p2)
{
Point p = new point();
p.x=p1.x+p2.x;
p.y=p1.y+p2.y;
return p;
}
public static Point operator +(Point p1,int a)
{
Point p = new point();
p.x=p1.x+a;
p.y=p1.y+a;
return p;
}
}

使用

1
2
3
4
5
6
7
8
9
Point p = new Point();
p.x = 1;
p.y = 1;
Point p1 =new Ponit();
P1.x = 2;
p1.y = 2;

Point p3 = p+p1;
Point p4 = p+2;

可重载和不可重载的运算符

可重载的运算符

()内部写的是需要传几个参数

算术运算符

+(2) -(2) *(2) /(2) %(2) ++(1) --(1)

逻辑运算符

!(1)

看到这里,你可能会疑惑,我要怎么去重载!这个运算符呢?

其实没有必要去纠结,运算符重载是很自由的,你可以自定义返回,它是布尔类型还是整形,抑或是浮点数

举个例子

1
2
3
4
5
6
7
8
9
10
11
public static bool operator !(Point p1)
{
return false;
}
/*
public static int operator !(Point p1)
{
return 0;
}
这两者都是可以的
*/

那么与(&&)或(||)这两个运算符呢,很遗憾的是,他们两个并不支持去重载。

位运算符

|(2) &(2) ^(2) ~(1) <<(2) >>(2)

条件运算符

>(2) <(2) >=(2) <=(2)

值得注意的是,刚才在上方我们也说了,条件运算符要成对出现。这代表着什么意思呢?

是说明,当存在>重载时,<也必须跟着重载

不可重载的运算符

  • 逻辑与(&&) 逻辑或(||)
  • 索引符([])
  • 强转运算符(())
  • 特殊运算符(点.三目运算符? :赋值符号 =)

练习题

Q1:

定义一个位置结构体或类,为其重载判断是否相等的运算符(x1,y1)==(x2,y2)两个值相同时才为true

Q2:

定义一个Vector3(x,y,z)通过重载运算符实现以下运算

(x1,y1,z1)+(x2,y2,z2)=(x1+x2,y1+y2,z1+z2)

(x1,y1,z1)-(x2,y2,z2)=(x1-x2,y1-y2,z1-z2)

(x1,y1,z1)*num1=(x1*num1,y1*num1,z1*num1)

答案

A1:

A2:

内部类和分部类

内部类

概念

在一个类中再申明一个类

特点

使用时要包裹者点出自己

作用

亲密关系的变现

注意

访问修饰符作用很大

实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Person
{
public int age;
public string name;
public Body body;
public class Body
{
Arm leftArm;
Arm rightArm;
class Arm
{

}
}
}

调用方法

使用时要包裹者点出自己

1
2
3
4
5
6
7
8
class Program
{
static void Main(string[] args)
{
Person p = new Person();
Person.Body = new Person.Body();
}
}

其实意义不大,分开写也无伤大雅

分部类

概念

把一个类分成几部分申明

关键字

partial

作用

分部描述一个类

增加程序的拓展性

注意

  • 分部类可以写在多个脚本文件中
  • 分部类的访问修饰符要一直
  • 分部类中不能有重复成员

实例

1
2
3
4
5
6
7
8
9
10
11
12
13
partial class Student
{
public bool sex;
public string name;
}
partial class Student
{
public int number;
public void Speak(string str)
{

}
}

分部方法

该方法局限性太大,了解即可

概念

将方法的申明和实现分离

特点

  1. 不能加访问修饰符,默认私有
  2. 只能在分部类中申明
  3. 返回值只能是void
  4. 可以有参数但不用,out关键字