C# 属性
封装性
含义
1. 字段和方法放到一个类中
2. 类中字段私有化,类中方法公开化
为私有化的添加一组方法
获取字段值的方法 Get***()
设置字段值的方法 Set***()
一个私有字段对应一个属性,属性其实有两个方法
只是在 写法简洁了一些。
class Role
{
private string roleName ;
private int age ;
public string RoleName
{
get { return roleName ; }
set { roleName = value ; }
}
public int Age
{
get { return age; }
set { age = value; }
}
}
Role r1 = new Role();
r1 . Age = -200 ;
Console.WriteLine( r1. Age );
属性语法:
public 返回值类型 属性名
{
get { return 字段名 ; }
set { 字段名 = value ; }
}
注:1.属性名和字段名是对应的,只是属性名应该首字母大写;
2.一个属性中对应两个方法:get 和 set
通过get访问字段的值,通过set设置字段的值
3.如何利用属性访问或设置值?
对象名.属性名 = 值 ;//设置值
对象名.属性名 ; //访问值
4.将具体值设置到字段上时,有一个隐含的变量value
是先将具体值交给value变量,再由value变量给
字段。value的类型会与当前操作的字段匹配。
总结 :
字段私有化,方法公开化
一个私有化字段对应一个标准属性(包含两个方法get|set)
练习:
创建一个单选试题类,类中的字段私有化,方法公开化
然后为私有化字段添加对应的标准属性。
通过属性来设置字段值,访问字段值
中午练习:
为 SingleQuestion.cs 类添加无参数和含有全部(4个)
的构造方法。
创建一个 测试类 , SingleQuestionTest2.cs
在测试类中,创建一道单选试题,对象名为:q2 ,
在创建这道试题时,通过构造方法的形式为对象的4个
字段设置值,设置值之后,调用Print()方法打印出这道试题
然后提示用户输入答案,用户输入答案后,判断用户答案
与 正确答案是否一致。然后提示“答对了”或“答错了”
1.如何实现封装----属性
2. 标准属性
1)特点
2)属性的两个方法
3)属性中的set,对数据进行业务逻辑处理
4)标准属性可设置 只读操作 ,只写操作
只读:只能访问字段的值,而不能为字段设置值
只写:只能为字段设置值,设置完值,是不能访问的。
当然,可以设置只读或只写权限,也可以设置既可读
也可写。
2. 自动属性(了解)
class Question
{
private int no ; //字段
//标准属性
public int No
{
get { return no ; }
set { no = value ;}
}
}
一个私有字段 + 一个标准属性
相当于:一个自动属性
public int No
{
get ;
set ;
}
练习:
创建一个Student类
类中包含两个字段:
学生姓名 ---- name 字段,标准的属性 Name
学生学号 ---- 自动属性 No
标准属性和自动属性
1.自动属性是 prop ,按两次Tab
不需要再自己定义私有字段,系统会在自动属性中
自动添加一个对应的私有字段
2.何时使用自动属性?
编码中,一般都是使用标准属性 。
但是,如果一个类中有大量的字段(如:50个)
但是对字段设置值或访问值时,只是做最简单的设置和访问
而不需要对数据做任何处理(如:比如,数据是否合法)
这时,就可以使用自动属性。
这表明,使用属性进行了封装,符合类的设计规则。
3.自动属性get和set必须成对出现,在自动属性 中
不能再设置只读或只写一种权限;
自动属性中不能在set中添加业务代码
对字段的值进行相应判断的操作。
练习:创建一个多选试题,MultiQuestion.cs,包含的字段:
字段:题号,题干,选项, 答案(多个 )
no text options answer
方法:Print(): 打印试题到控制台方法
Check( string[] inputAnswers ):判断试题正误
构造方法
要求:字段应该使用自动属性来实现。
string answer = "A,B,C" ;
string[] ans = answer .Split( ',' );
----------------------------------------------------------
继承性
提高代码复用性
子父类
共有的内容提取出来,作为父类
其它的类中,如果使用 共有的内容,继承父类
单选试题 :题号,题干,选项,答案(1个 )
构造方法
Print()
Check( string inputAnser)
多选试题: 题号,题干,选项,答案(多个)
构造方法
Print()
Check( string[] inputAns)
1. C# 中的继承,子父类关系
2. C# 中的继承符号: 冒号
子类类名的后面加上冒号,冒号跟的是一个父类的类名
3.C#中的继承是单层继承
4.C#中的继承具有传递性
class A { } --- 爷爷 A
class B : A { } --- 父亲 B
class C : B { } --- 儿子 C
C类继承了B类,C就具备了B类的所有内容,
B类又继承了A类,B类就具备了A类的所有内容,
而对于C来说,C类不光具备了B类的内容,
同时,隐式的具备了A类中的内容。
5. 子类继承了父类,可以继承父类的哪些内容?
---全部内容都会被子类继承
当然,全部内容有一些比较特殊的:
1) 父类私有的内容:
表面上看,是访问不到,但是实际是继承了
只是暂时访问不到。
将来,可以通过反射等操作拿到相关数据 )
2) 父类的构造方法
构造方法是不能继承的,但是可以子类可以使用
(??????)
6. 如果父类有了内容,子类又定义了相同的内容,
用子类对象调用时,究竟会调用谁的?
virtual override new base
------------------------------------------------------
总结:
1.封装性
封装的意义
如何实现封装?
标准属性
自动属性 (了解)
2.继承性
继承性的意义
继承的基础语法
继承的基本特点
继承中的关键字: vitural override new base
作业1:
上课代码,SingleQuestion.cs
MultiQuestion.cs
Test.cs
要求:创建单选试题,多选试题,然后提示用户输入
答案,并判断结果。
作业2:
创建试题类,父类,Question.cs
--题号,题干,选项
--构造方法(无参数构造方法,含有三个参数构造方法)
打印试题到控制台方法Print()
创建单选试题类,SingleQuestion.cs
-- 继承了试题类,
-- 添加自己特性的内容:
private string answer;
Check( string answer )
要求:字段私有化,为私有化字段添加标准属性
创建多选试题类,MultiQution.cs
-- 继承了试题类,
-- 添加自己特性的内容:
private string[] answer;
Check( string[] answer )
要求:字段私有化,为私有化字段添加标准属性
创建测试类。
day11 (2019.4.16) (2018.01.15.Tuesday)
属性
day11 2018.01.16 周二
----------------------------------------------------------
封装性:如何设计一个类
继承性:如何实现代码重复利用
继承基本内容:
1)子父类
2):
3)单层继承
4)传递性
5)全部继承(私有,构造方法)
6)构造方法
7) virtual override new
virtual : 父类方法返回值前加 virtual
override: 子类方法返回值前加 override
表示继承了父类的中的某些方法,方法不是特别适合子类,
子类就可以在 继承过来的基础上,再进行适当的重新修改,
“重写”。
new : 当父类和子类都有相同的方法,子类明确
表示不想使用父类的方法,并且不想继承父类
的这个方法,这时,需要在子类的这个方法
最前面加:new,表示隐藏父类相同名字的方法。
--------------------------------------------------------
练习:测试new关键字的使用场景
创建一个类库项目,创建一个 工具类,工具类一个
方法: public void ShowClassMessage()
创建一个 项目,项目下一个类,项目中需要导入一个第三方
类库, 类中定义了一个和类库中同名的方法,如何操作 ?
1.代码详见:“new关键字的使用”文件夹下内容
2.详细步骤:
1) 创建了一类库项目 .net framework
2) 类库项目下创建一个类,ClassUtils.cs
类中添加一个方法: ShowClassMessage()--一句话
3) 右击类库项目 --- 生成
注:找到生成的 .dll 的文件(当前类库项目所在目录
--bin---Debug--****.dll )
4) 将***.dll文件拷贝到桌面
5) 创建一个普通的控制台应用程序
导入桌面上的 .dll文件 : 右击引用--添加引用--浏览
6) 控制台项目中创建一个类,NewDemo.cs
继承 .dll 类库中的某个类( ClassUtils.cs)
继续NewDemo.cs中添加一个 方法:ShowClassMessage()--
7) 编译期间:给出绿色的警告信息:
是否需要显示的隐藏父类中的方法,使用new关键字
练习:创建图形类,Shape
字段:名字 name
方法:求周长和求面积的方法(定义时定义为虚方法)
构造方法
创建图形类的子类:矩形类Rectangle
---字段:width ,height
构造方法
圆形类:Circle,
-- 字段:radius 半径
构造方法
要求:子类中对求周长和面积的方法进行重写。
代码详见:DAY11_02_OOP05
-------------------------------------------------------
父类 子类构造方法调用先后
当创建一个子类对象时,先进入子类构造方法
在子类每个构造方法的小括号后面,其实都默认省略了
:base(),先调用父类的无参数构造方法,然后才是
子类当前的构造方法。
1) 不写:base(),调用父类无参数
2) 写 :base(), 调用父类无参数
3) 写 :base( *** )调用父类对应形式的构造方法
上面所有内容说明:
----创建子类对象,一定会先调用父类相应的构造方法----
----调用父类无参数的还是有参数的,有几个参数的,
取决于子类构造方法小括号后面使 :base(参数)
继承关系中的构造方法负责的工作:
有时候,创建对象时通过构造方法为字段赋值,
有些字段是继承父类得来的,在子类中直接为字
些字段赋值是不可取的,如何破?
---谁的字段交给谁初始化(赋值)----
如果是父类的字段,就要使用:base()的形式
让父类自己去赋值。
子类的特性内容,让子类自己赋值。
练习:为单选试题类添加含有4个参数的构造方法,
其中前3个参数(题号,题干,选项)应该交给父类的
的构造方法去完成(即:使用 :base(,,,)
然后为父类添加含有3个参数的构造方法,
最后创建一个测试类,测试类中创建一道单选试题,
要求:创建试题时,通过构造方法为试题的字段赋值。
然后打印这道试题(只打印,不用输入答案判断)
代码详见:DAY11_01_OOP5 项目
中午练习:
在当前类的基本上,补全“矩形类”:
1) 矩形类添加字段:长和宽,width ,height
2) 为字段添加2个标准属性
3) 重 写父类的求周长和求面积的方法。
矩形周长:2*(长+宽)。 矩形面积:长*宽
4) 创建一个测试类,测试类中创建矩形对象,然后
通过属性为字段赋值,打印矩形的 周长和面积
在“Shape”图形类中添加无参数构造方法和含有一个参数构造
在“Circle”圆形类中添加无参数,含有2个参数的构造方法
其中第一个参数表示图形的名称,这个参数要交由父类赋值
另外一个参数就是当前圆的半径,这个参数子类自己赋值。
矩形类也是类似的,不再详细描述。
创建测试类,通过构造方法为对象赋值,测试周长和面积。
代码详见:DAY11_01_OOP5 项目下的:
Shape.cs
Circle.cs
Rectangle.cs
ShapeTest1.cs--测试创建圆的对象,利用属性为对象赋值
ShapeTest2.cs--测试创建圆的对象通过构造方法为对象赋值
ShapeTest3.cs--测试创建矩形对象通过构造方法为对象赋值
--------------------------------------------------
3. base 关键字的使用:
1. 子类构造方法的小括号后面使用:
:base() 或 :base( 参数列表)
2. 在子类重写了父类的那个方法的 方法体中,
使用 base.方法名() 来表示调用父类的方法
比如:圆类重写了图形类中的求周长和求面积的方法,
在圆类中的求面积的方法中,return 后面使用了base.
------------------------------------------------------
代码详见:DAY11_01_OOP5项目下:
Circle.cs---GetArea()方法
BaseTest.cs ---测试类
---------------------------------------------------------
多态性
1. Question q = new SingQuestion();
父类变量,创建子类对象
父类变量指向子类对象
父类引用指向子类对象
父类引用引用子类对象
练习:创建一个汽车类,Car.cs,父类,作为 父类
--字段:汽车品牌
--方法:汽车介绍 Introduce( )
构造方法(无参数,含有一个参数)
汽车类创建多个子类:
Benz.cs , 奔驰车
Audi.cs ,奥迪车
BMW.cs , 宝马车
汽车测试类 :CarTest
1.向上转型
使用“父类变量指向子类对象”的方式创建对象的过程
称为 向上转型。
2.向上转型后,这时,这个对象就具备了2种类型:
一种类型是:父类型
另外一种类型: 子类
根据运行期间对象的所属类型来决定该执行子类还是父 类
中的方法。如果子类重写了,执行子类自己的,如果子类
没有重写,执行父类的,如果父类,就会报错。
如: Car c = new Benz();
这时,c 就有两种类型,1种类型是属于:Car 类型
另外一种类型属于 Benz()类型。
代码阶段,都属于Car类型,运行期间,会是奔驰类型的。
1. Car c = new Benz();
多态
c.******* ( Car 类中的内容)
c.Introduce();
2. 向上转型后,对于 c 的两种类型:
Car类型,Benz类型)
-------------------------------------------------------
多态数组
方法参数
方法返回值
Person
{
public void Drive( Car c )
{
}
}
Person p1= new Person();
Car c = new Benz() ;
p1.Drive( c );
分析: 游戏树V1.0
在这个案例中,是集合了封装、继承、多态的综合案例。
--------------------------------------------------------------
1.封装体现在:设计4个实体类时,这4个类中的字段和方法进行限制。
Role -- 角色类
Magic --魔法师类
soldier --战士类
要求:类中的字段私有化,然后为私有化字段添加标准属性。
方法公开化,然后添加构造方法。
2.继承体现在:
Role ---- 角色类,父类
Magic ---- 魔法师角色,子类
soldier --- 战士角色, 子类
要求:Role类中定义了角色名称,定义了进攻的方法
战士类和魔法师类继承了角色类,重写了Role类中的Attack()方法。
另外,使用了 :base( roleName )显示的调用父类含有一个参数构造
方法为父类的 roleName 字段赋值。
4. 多态体现在:
设计 Team 类
Team 类中的成员:
1) 一个Role类型的数组,存储团队中的多名不同的角色
注:该数组既可以存储魔法师成员,又可以接收战士角色的成员
最多只能包含6个成员,如果超过,给出错误提示。
2) void AddMemeber( Role r )
该方法用于向Role数组中添加角色成员。
这里的参数为 Role 类型,这样保证了只要使用父类变量指向
子类对象的方式创建对象,将对象传给 参数 r时,r就能正常
接收。也就是:r 保证了可以接收多种类型的角色(魔法师或战
3) int AttackSum():获取整个团队中的总伤害值
该方法中遍历Role数组,获取数组中每个角色成员对敌人的
进攻伤害值,所有角色成员伤害值相加,就是最后结果。
遍历 Role数组时,使用数组中的每个元素调用 Attack()
会根据具体 角色 来 选择执行Attack()
当数组成员为Magic时,且Magic中重写了父类的Attack()
方法,那么编译器会执行Magic类中的Attack(),而不会执行
父类Role类中的Attack();
同样,如果角色成员 为soldier时,且soldier 重写了Attack()
会调用子类自己的Attack()方法。
最后:要求组建一个团队,并创建多个成员,然后将成员通过
AddMember()方法添加到团队中。添加之后,调用
AttackSum()方法,计算整个团队进攻时,整个团队的
整体攻击伤害值。