深入.NET平台和C#编程
第一章 深入.NET框架
1.1 Microsoft .NET框架概述
1.1.1 Microsoft .NET介绍
Microsoft .NET平台利用以互联网为基础的计算机和通信激增的特点,通过先进的软件技术和众多的智能设备,从而更简单、更有效的互联网服务。
1.1.2 .NET框架的魅力
.NET是开发.NET应用程序的核心基础,.NET框架提高了软件的可复用性、可扩展性、可维护性和灵活性;对Web应用的强大支持。
1.2 .NET框架体系结构
1.2.1 .NET框架结构
(1)组成:
主要包含公共运行语言时(CLR)和框架类库(.NET Framework)。
1.2.2 CLR
(1)CLR的理解:
CLR全称公共运行语言时,它是所有.NET应用程序运行时的环境,是所有.NET应用程序都要使用的编程基础。
(2)CLR的组成:
包含三个组成部分CLS(公共语言规范)和CTS(通用类型系统)以及MSIL(中间语言)。
1.2.3 FCL
(1)FCL的理解:一部分被封装好的功能的集合。
(2).NET的核心类库:
System : 此命名空间包含所有其他的命名空间。
System.Collect.Generic : 支持泛型操作。
System.IO :支持对文件的操作。
System.NET : 支持对网络协议的编程。
System.Data : 提供对表示ADO.NET结构类的访问。
System.Windows.Forms : 用于开发Windows应用程序。
System.Drawing : 支持GDI+基本图形操作。
1.3 面向对象回顾
1.3.1 类和对象
(1)类和对象的理解:
类定义了一组概念的模型,而对象是真正的实体。关系如下:
1、由对象归纳类,是归纳对象共性的过程。
2、在类的基础上,将状态和行为实体化为对象的过程称为实例化。
3、只写属性:只包含set访问器。
4、只读属性:只包含get访问器。
5、读写属性:同时包含get和set访问器。
举例:
private string _name;
public string Name
{
get{return _name;}
set{_name=value;}
}
1.3.2 封装
(1)封装的理解:将内部私有的属性将其保护起来。
(2)封装的好处:
1、保证数据的安全性
2、提供清晰的对接口
3、类内部实现可以任意修改,不影响其他类
第二章 深入C#数据类型
2.1 值类型和引用类型
2.1.1 概述
(1)值类型:
值类型源于System.VauleType,值类型主要包括数据类型(如int,double,float)和枚举类型。
例如:
class Program
{
static void Main(string[] args)
{
int heightZhang = 170;
int heightLi = heightZhang;
Console.WriteLine("去年张浩的身高是:"+heightZhang+",李明的身高是:"+heightLi);
heightLi = 180;
Console.WriteLine("今年张浩的身高是:"+heightZhang+", 李明的身高是:"+heightLi);
}
}
(2)引用类型:
引用类型源于System.Object家族,在C#中引用类型主要包括数组、类和接口。
例如:
class Program
{
static void Main(string[] args)
{
int[] infoZhang = new int[] { 170, 60 };
int[] infoLi = infoZhang;
Console.WriteLine("去年--张浩的身高是:" + infoZhang[0] + "体重是:" + infoZhang[1] + ",李明的身高是:" + infoLi[0] + "体重是:" + infoLi[1]);
infoLi[0] = 180;
infoLi[1] = 70;
Console.WriteLine("今年--张浩的身高是:" + infoZhang[0] + "体重是:" + infoZhang[1] + ",李明的身高是:" + infoLi[0] + "体重是:" + infoLi[1]);
Console.ReadLine();
}
}
(3)细分值类型和引用类型:
值类型 | 引用类型 |
---|---|
基本数据类型(int,long,float,double,char) | 类(string,class) |
枚举类型(enum) | 接口(interface) |
结构类型(struct) | 数组(int[],string[]) |
2.1.2 结构
(1)结构的定义:
1、语法:
访问修饰符 struct 结构名
{
//结构体
}
//结构可以有方法也可以有字段
//定义时,结构中的字段不能被赋初始值
2、结构的使用
结构的构成和类相似,在使用时注意以下几点:
1.可以不用new,直接定义结构的对象
2.声明结构的对象后,必须给结构的成员赋初始值
3、举例:
class Student
{
public int _id;
public int _age;
public int Id
{
get { return _id; }
set { _id = value; }
}
public int Age
{
get { return _age; }
set { _age = value; }
}
public void Show()
{
Console.WriteLine("ID:{0}\n年龄:{1}", _id, _age);
}
}
class Program
{
static void Main(string[] args)
{
Student stu = new Student();
stu.Id = 1001;
stu.Age = 20;
stu.Show();
}
}
2.1.3 拆箱和装箱
(1)拆箱和装箱的理解:
拆箱:拆箱是引用类型转化为基本类型
装箱:装箱是基本类型转化为引用类型
例如:
static void Main(string[] args)
{
int i = 123;
object o = i;//装箱
i = 456;//改变i的内容
Console.WriteLine("值类型的值为{0}",i);
Console.WriteLine("引用类型的值为{0}", o);
}
static void Main(string[] args)
{
int i = 123;
object o = i;//拆箱
int j = (int)o;
Console.WriteLine("j的值现在为:" + j);
Console.ReadLine();
}
2.2 不同类型的参数传递
2.2.1 概述
(1)使用值传递,在方法中对参数值的更改在调用后不保留。
(2)使用ref方式传递,可以保留对参数值的更改。
2.2.2 值方式参数传递
在值方式传递参数时,参数可以是引用类型,也可以是值类型。
(1)使用引用类型作为参数:
class Program
{
public void Vote(Class1 se)
{
//人气值增加1
se.Popularity++;
}
static void Main(string[] args)
{
Class1 zhang = new Class1();
zhang.Age = 25;
zhang.Name = "张靓";
zhang.Gender = "1201";
zhang.Popularity = 10;
//投票前
MessageBox.Show(zhang.SayHi());
Program voter = new Program();
voter.Vote(zhang);//引用类型做参数
//投票后
MessageBox.Show(zhang.SayHi());
}
}
(2)使用值类型传递:
class Program
{
public void Vote(StructSE se)
{
//人气值增加1
se.Popularity++;
}
static void Main(string[] args)
{
StructSE zhang = new StructSE();
zhang.Age = 25;
zhang.Name = "张靓";
zhang.Gender = "1201";
zhang.Popularity = 10;
//投票前
MessageBox.Show(zhang.SayHi());
Program voter = new Program();
voter.Vote(zhang);//值类型做参数
//投票后
MessageBox.Show(zhang.SayHi());
}
}
2.2.3 引用方式参数传递
在引用方式传递参数时,参数可以是引用类型,也可以是值类型。
(1)使用引用类型作为参数:
public void Vote(ref Class1 se)
{
//人气值增加1
se.Popularity++;
}
static void Main(string[] args)
{
Class1 zhang = new Class1();
zhang.Age = 25;
zhang.Name = "张靓";
zhang.Gender = "1201";
zhang.Popularity = 10;
//投票前
MessageBox.Show(zhang.SayHi());
Program voter = new Program();
voter.Vote(zhang);//引用类型做参数
//投票后
MessageBox.Show(zhang.SayHi());
}
(2)使用值类型作为参数:
public void Vote(Class1 se)
{
//人气值增加1
se.Popularity++;
}
static void Main(string[] args)
{
StructSE zhang = new StructSE();
zhang.Age = 25;
zhang.Name = "张靓";
zhang.Gender = "1201";
zhang.Popularity = 10;
//投票前
MessageBox.Show(zhang.SayHi());
Program voter = new Program();
voter.Vote(zhang);//值类型做参数
//投票后
MessageBox.Show(zhang.SayHi());
}
第三章 使用集合组织相关数据
3.1 集合概述
3.1.1 ArrayList
(1)ArrayList的理解:
ArrayList非常类似于数组,也有人称它为数组列表,ArrayList可以动态维护。ArrayList类属于System.Coolections命名空间,使用它使一定要导入命名空间。
using System.Coolections;
//创建容量为0的ArrayList对象
ArrayList stu = new ArrayList();
//创建容量为5的ArrayList对象
ArrayList stu1 = new ArrayList(5);
(2)ArrayList常用的方法和属性:
属性名称 | 说明 |
---|---|
Count | 获取ArrayList中实际包含的元素数 |
返回值 | 方法名称 | 说明 |
---|---|---|
int | Add(Object value) | 将对象添加到ArrayList的结尾处 |
void | Remove(int index) | 移除ArrayList指定索引处的元素 |
void | RemoveAt(Object vaule) | 从ArrayList中移除特定元素 |
void | Clear() | 从ArrayList中移除所有元素 |
(3)ArrayList的遍历:
for:借助下标
for(int i = 0; i < ArrayList.Count; i++)
{
cw(ArrayList[i]);
}
foreach:借助中间变量
foreach(Object obj in ArrayList)
{
cw(obj);
}
3.1.2 Hashtable
(1)Hashtable的理解:
Hashtable的数据结构统称为哈希表,也有人称它为“字典”,Hashtable的数据时通过键(Key)和值(Value)来组织的。Hashtable属于System.Coolections命名空间,它的每一个元素都是键\值对。
using System.Coolections;
//创建对象
Hashtable ht = new Hashtable();
(2)Hashtable常用的属性和方法:
属性名称 | 说明 |
---|---|
Count | 获取包含在Hashtable中的键/值对的数目 |
Keys | 获取包含在Hashtable中键的集合 |
Values | 获取包含在Hashtable中值的集合 |
返回值类型 | 方法名称 | 说明 |
---|---|---|
void | Add(Object key,Object values) | 将带有指定键和值的元素添加到Hashtable中 |
void | Remove(Object key) | 从Hashtable移除带有特定键的元素 |
void | Clear() | 从Hashtable中移除所有元素 |
(3)Hashtable的遍历:
//得到所有的Value
foreach (Object cvb in ht.Values)
{
Console.WriteLine(cvb);
}
//得到所有的key
foreach (int item in ht.Keys)
{
Console.WriteLine(item);
}
3.2 泛型和泛型集合
3.2.1 泛型
(1)泛型的理解:
泛型是C#2.0中的一个新特性。通过泛型可以最大限度地重用代码,保护类型的安全和提高性能。泛型集合可以约束它所储存的对象类型,List和Dictionary<K,V>访问元素无需进行类型转换。
3.2.2 泛型集合List
(1)泛型集合List语法及理解:
List<T> 对象名 = new List<T>();
""中的T表明集合中管理的元素类型,对集合元素类型进行约束。
(2)List常用的方法和属性:
属性名称 | 说明 |
---|---|
Count | 获取List中实际包含的元素数 |
返回值 | 方法名称 | 说明 |
---|---|---|
int | Add(T value) | 将对象添加到List的结尾处 |
void | Remove(int index) | 移除List指定索引处的元素 |
void | RemoveAt(T vaule) | 从List中移除特定元素 |
void | Clear() | 从List中移除所有元素 |
(3)List的遍历:
for(int i = 0; i < list.Count;i++)
{
list[i];
}
foreach(T item in list)
{
cw(item);
}
(4)泛型List与非泛型ArrayList的区别:
异同点 | List | ArrayList |
---|---|---|
不同点 | 对所保存元素进行类型约束。添加/读取值类型元素无需拆箱和装箱。 | 可以增加任何类型。添加/读取值类型元素需拆箱和装箱。 |
相同点 | 通过索引访问集合的元素。添加元素方法相同。 | 删除元素方法相同。 |
3.2.3 泛型集合Dictionary<K,V>
(1)泛型集合Dictionary<K,V>的理解和语法:
泛型集合Dictionary<K,V>它具有泛型的全部特征,编译时检查类型约束,获取元素无需进行类型转换,存储方式和Hashtable相似。
Dictionary<K,V> 对象名 = new Dictionary<K,V>();
//<K,V>中K表示集合中Key的类型,V表示Value的类型
//null不能作为key,编译的报错,运行的时候
(2)Dictionary<K,V>常用的属性和方法:
属性名称 | 说明 |
---|---|
Count | 获取包含在Dictionary中的键/值对的数目 |
Keys | 获取包含在Dictionary中键的集合 |
Values | 获取包含在Dictionary中值的集合 |
返回值类型 | 方法名称 | 说明 |
---|---|---|
void | Add(Object key,Object values) | 将带有指定键和值的元素添加到Dictionary中 |
void | Remove(Object key) | 从Dictionary移除带有特定键的元素 |
void | Clear() | 从Dictionary中移除所有元素 |
(3)Dictionary<K,V>的遍历:
//得到所有的Value
foreach (Object cvb in dic.Values)
{
Console.WriteLine(cvb);
}
//得到所有的key
foreach (int item in dic.Keys)
{
Console.WriteLine(item);
}
(4)泛型Dictionary<K,V>与非泛型Hashtable的区别:
异同点 | Dictionary<K,V> | Hashtable | |||
---|---|---|---|---|---|
不同点 | 对所保存元素进行类型约束。添加/读取值类型元素无需拆箱和装箱。 | 可以增加任何类型。添加/读取值类型元素需拆箱和装箱。 | |||
相同点 | 通过Key获取Values。添加元素方法相同。 | 删除元素方法相同。b遍历方法相同。 |
3.2.4 泛型类
(1)语法:
public class 类名<T>
{
//.........
}
//T是类型参数,代表具体的数据类型,可以是类参数,也可以是基本数据类型
(2)泛型的优点:
1、性能高:泛型无需进行类型的转换操作。
2、类型安全:泛型集合对它所存储的对象进行了类型的约束。
3、实现代码的重用:泛型相当于模板,它支持任何数据类型。
第四章 深入类的方法
4.1 构造函数
(1)构造函数的语法:
访问修饰符 类名(参数列表)
{
//方法体
}
(2)类的构造函数的特点:
(1)方法名与类名相同
(2) 没有返回值类型
(3)主要完成对象的初始化工作
**(3)构造函数的作用:**用来new对象,兼职给成员变了赋值。
(4)分类:
显示方式:
隐式:隐藏的无参
1、就是创建一个类,没有手写构造函数的时候当前类自带的构造函数
2、就是无参的构造函数
显示:自定义构造
就是自定义构造函数
参数的格式:
有参:类名()括号里有参数
无参:类名()括号里没有参数
(5)注意事项:
只要定了一个类:如果没有手写构造函数,那么这个类会自带一个无参的构造函数,并且这个构造函数比隐藏
只要你手写了构造函数,那么这个类就不会存在隐藏构造函数【不会有默认的无参构造函数】
【建议:自定义类请自定义无参构造函数】
【要求:每一个自定义的class不管任何情况都请加上无参构造函数】
4.2 方法重载
4.2.1 构造函数的重载
(1)重载的特点:
1、方法名相同
2、方法参数类型不同或者参数个数不同
3、在同一个类中
(2)调用规则:
根据参数[个数+类型]
**注:【**不能】以【返回值类型】来决定是否是重载
【不能】以【访问修饰符】来决定是否是重载
4.2.2 方法重载示例
public Car(string name,string ys,string cd)
{
this.Name = name;
this.Ys = ys;
this.Cd = cd;
Console.WriteLine("我是一辆" + Name + "颜色" + Ys + "产地" + Cd);
}
public Car(string name, string ys, string cd,int sd)
{
this.Name = name;
this.Ys = ys;
this.Cd = cd;
this.Sd = sd;
}
public void Run()
{
Console.WriteLine("我是一辆" + Name + "颜色" + Ys + "产地" + Cd + "车速" + Sd);
Console.ReadLine();
}
第五章 初识继承与多态
5.1 继承的概述
5.1.1 继承的概念
大致的来说就是子承父,也就是说一个类可以继承另一个类,被继承的类称为父类(基类),继承其他的类称为子类(派生类)。继承是面向对象编程中的一个非常重要的特征。
5.1.2 base关键字和protected修饰符
**(1)base关键字:**它表示父类,可以访问父类的成员。例如父类的属性、方法。
例如:
public string SayHi()
{
string message;
message = string.Format("大家好,我是{0},今年{1}岁,项目管理经验{2}年", base.Name, base.Age, this.YearOfExperience);
return message;
}
**(2)protected修饰符:**protected修饰符这个访问修饰符修饰的成员允许被子类访问,而不允许其他非子类访问。
例如:
public class Employee
{
protected string ID { get; set; }//工号
protected int Age { get; set; }//年龄
protected string Name { get; set; }//姓名
protected Gender Gender { get; set; }//性别
}
public class PM : Employee
{
public PM(string id, string name, int age, Gender gender, int yearOfExperience)
{
this.ID = id;
this.Name = name;
this.Age = age;
this.Gender = gender;
this.YearOfExperience = yearOfExperience;
}
}
5.1.3 子类构造函数
**(1)隐式构造函数:**当没有指明调用父类的哪一个构造函数时,系统会隐式地调用父类的无参构造函数。
**(2)显示构造函数:**在C#中只要在子类的构造函数后添加“:base(参数列表)”,就可以知道该子类的构造函数调用父类的哪个构造函数。
例如:
public Truck(string type,string place) : base(type, place)
{
}
//参数的变量名必须和父类的构造函数参数名一致
//指明调用父类的哪一个参数
5.2 继承的使用
5.2.1 继承的特性
**(1)继承的传递性:**如果class A:B,class:C,A也可以访问C的成员。继承需要符合is a 的关系。
**(2)继承的单根性:**一个类不能同时继承多个父类。
5.2.2 is a 的应用
(1)作用:is关键字用来判断对象是否属于给定的类型,如果属于返回true,否则返回false。
例如:
static void Main(string[] args)
{
SE ai = new SE("112", "艾边成", 25, Gender.男, 100);
SE joe = new SE("113", "Joe",30,Gender.男,200);
PM pm = new PM("890", "盖茨",50,Gender.男,30);
List<Employee> employees = new List<Employee>();
employees.Add(ai);
employees.Add(joe);
employees.Add(pm);
foreach (Employee item in employees)
{
if(employees is SE)
{
Console.WriteLine(((SE)employees).SayHi());
}
if(employees is SE)
{
Console.WriteLine(((PM)employees).SayHi());
}
}
}
5.2.3 继承的价值
(1)继承模拟了现实世界的关系,OOP中强调一切皆对象,符合面向对象的编程思想。
(2)继承实现了代码的重用,合理的使用基础,使代码更加简洁。
(3)继承使得程序结构更加清晰,子类和父类的层次结果更加清晰。
5.3 多态
5.3.1 什么是多态
**多态的概念:**一种事物的多种形态。指同一操作作用于不同的对象时,可以有不同的解释,产生不同的执行效果。
5.3.2 多态的实现方式
1、方法重写:
(1)虚方法:使用virtual关键字修饰的方法,称为虚方法,虚方法有方法体。
语法:
//父类:
访问修饰符 virtual 返回值类型 方法名()
{
//方法体
}
//(方法重写)子类
访问修饰符 override 返回值类型 方法名()
{
//方法体
}
例如:
public virtual string SayHi()
{
string message = string.Format("大家好!");
return message;
}
public override string SayHi()
{
string message;
message = string.Format("大家好,我是{0},今年{1}岁,项目管理经验{2}年",this.Name,this.Age,this.YearOfExperience);
return message;
}
2、重写的特点:
(1)不同的类。
(2)被重写的方法,方法名+参数必须和父类一模一样。
(3)被子类重写的方法,在父类中必须明确标注出,当前方法可以被子类重写。
(4)如果子类当前方法是在重写父类的方法,那么必须用overrirde标注。
第六章 深入理解多态
6.1 里氏替换原则
(1)里氏替换原则的概念:
里氏替换原则(LSP)所有引用父类的地方,都可以透明的使用子类对象。
(2)里氏替换原则的应用:
里氏替换原则是软件应该遵守的重要原则之一。有了里氏替换原则才使继承复用成为可能。
例如:
//父类 鸟类
public class Bird
{
public double Speed{get;set;}
public void Fly(){}
}
//子类 鸵鸟类
public class Ostrich:Bird
{
//......
}
**注:**里氏替换原则子类对象可以代替父类对象,反之父类对象不能代替子类对象。
(3)is和as操作符的使用:
1、is操作符:用于检查对象和指定的类型是否兼容。
例如:
for (int i = 0; i < employees.Count; i++)
{
if(employees[i] is SE)
{
//...
}
if (employees[i] is PM)
{
//...
}
}
2、as操作符:主要用于两个对象之前的类型转换。
例如:
for (int i = 0; i < employees.Count; i++)
{
if(employees[i] is SE)
{
SE se = employees[i] as SE;
Console.WriteLine(se.SayHi());
}
if (employees[i] is PM)
{
PM pmm = employees[i] as PM; Console.WriteLine(pmm.SayHi());
}
}
6.2 抽象类和抽象方法
6.2.1 什么是抽象类和抽象方法
(1)抽象方法的概念:
抽象方法是一个没有实现的方法,通过在定义方法是增加abstract关键字来声明抽象方法。
(2)抽象方法的语法:
访问修饰符 abstract 返回值类型 方法名();
(3)抽象类的概念:
含有抽象方法的类就是抽象类。
(4)抽象类的语法:
访问修饰符 abstract class 类名{}
例如:
public abstract class TrafficTool
{
public abstract void Run();
}
6.2.2 抽象类和抽象方法的应用
(1)如何实现抽象方法:
抽象方法必须在其子类中实现,除非它的子类也是抽象类。与子类重写父类的虚方法一样,在子类中使用override关键字重写抽象方法。
语法:
访问修饰符 override 返回类型 方法名();
例如:
public class Tube:TrafficTool
{
public override void Run()
{
Console.WriteLine("地铁运行中!");
}
}
(2)抽象类的注意事项:
1、抽象类不能被实例化
2、不能是密封或是静态的
3、抽象类的抽象方法要在其子类中通过override关键字重写,除非子类也是抽象类。
6.3 虚方法和抽象方法的区别
虚方法 | 抽象方法 |
---|---|
用virtual修饰 | 用abstract修饰 |
要有方法体,即使是一个分号 | 不允许有方法体 |
可以被子类override | 必须被子类override |
除了密封类外都可以定义 | 只能在抽象类中定义 |
6.4 面向对象的三大特征
(1)封装:保证对象自身数据的完整性和安全性。
(2)继承: 建立类之间的关系,实现代码的复用,方便系统的扩展。
(3)多态: 相同的方法调用可实现不同的实现方式。