深入C#的学习
一、.NET 平台和C#编程
1、Microsoft.NET 框架概述
Microsoft.NET 平台通过先进的软件技术和众多的智能设备,从而提供更简单、更为个性化、更有效的互联网服务。.Net的战略目标是在任何时候、任何地方、使用任何工具都能通过.NET 的服务获得网络上的任何信息,享受网络带给人们的便捷与快乐。我们对于.net框架还有另外一个称呼——.NET Framework。为支持.NET 框架上的开发,微软公司发布了世界级开发工具VS,通过VS工具和.NET 框架的配合,能够方便快捷的开发出多种.NET 应用程序,还可以进行测试、版本控制、Team开发和部署等。
2、.NET 框架特点
(1)提供了一个面向对象的编程环境、完全支持面向对象编程、.NET 框架提高了软件的可复用性、可扩展性、可维护性和灵活性;
(2)对web的强大支持;
(3)对web服务的支持,web服务是.NET 非常重要的内容,它可以实现应用程序之间的相互通信;
(4)实现SOA、支持云计算;
(5)支持构建.NET 程序的炫彩外衣。
3、.NET 框架结构
.NET 框架运行在操作系统之上,是.NET 最基础的框架。他提供了创建、部署和运行.NET 应用的环境,主要包含公共语言进行时(CLR)和框架类库(FCL),并且支持多种开发语言,也就是跨语言开发,支持的语言有:C#、VB、.NET 、C++等。
大家知道,我们以前学过java,那么Java和.NET 有什么不一样的呢?关于.NET 和Java的对比我们常说:“Java是一个跨平台的语言,而.NET 是一个跨语言的平台“。
(1)CLR(公共语言进行时)
CLR是.NET 框架的基础,它的全称是公共语言进行时,包含CTS和CLS。它是所有.NET应用程序运行时环境,是所有.NET应用程序都要使用的基础。
为了实现跨语言开发和跨平台的战略目标,微软退出将代码编译成中间代码MSIL,它将由JIT编译器转换成机器代码。
CTS(通用类型系统),C#和VB.NET都是CLR的托管代码,它们的语法和数据类型各不相同。而通用类型系统用于解决不同语言数据类型不同的问题,所有的.NET语言共享这一类型系统,在它们之间可以实现无缝互操作。
CLS(公共语言规范),编程语言的区别不仅在于类型、语法或者说语言规范也都有很大的区别。CLS是一种最低的语言标准,它制定了一种以.NET平台为目标的语言所必须支持的最小特征,以及与其他的.NET语言之间实现互操作性所需要的完备特征,.NET框架下的语言都可以实现互相调用。
(2)FCL(框架类库)
FCL是一个综合性的面向对象的可重用类型集合,利用他不仅可以开发传统命令行应用程序,而且可以开发winforms应用程序及基于ASP.NET 的应用程序。
FCL提供了对系统功能的调用、是建立.NET应用程序、组件和控件的基础。
.NET的核心类库及其功能
(1)System:此命名空间包含所有的其他命名空间,它还有一个非常重要的数据类型“Object”,Object类是所有其他的.NET对象继承的基本类;
(2)System.Collections.Generic:支持泛型操作;
(3)System.IO:支持对文件的操作,如复制、粘贴、删除及对文件的读写等;
(4)System.Net:支持对网络协议的编程;
(5)System.Data:提供对表示ADO.NET结构的类的访问;
(6)System.Windows.Forms:用于开发Windows应用程序;
(7)System.Drawing:支持GDI+基本图形操作。
4、.NET Framework 3.0后的新特性
(1)WPF
WPf是微软Vista操作系统的核心开发库之一,它不仅是一个图形引擎,而且给windows应用程序的开发带来了一次革命。
(2)WCF
WCF把web服务、.NET Remoting等技术统一到单个面向服务的编程模型中,以实现真正的分布式计算。
(3)WF
WF是一个广泛通用的工作流框架,并且是从上到下在每个级别都针对扩展性进行了设计。
(4)Windows CardSpace
Windows CardSpace是微软公司取代用户名和密码成为验证网络使用者身份的新方法,不仅有反钓鱼功能还有预防其他类型的网络诈骗。
(5)LINQ
LINQ使得开发人员可以使用面向对象的语法查询数据,可以为SQL Server数据库、XML文档、ADO、.NET数据集等各种数据源编写。
5、类和对象的回顾
类定义了一组概念的模型,而对象是真正的实体。对于类的属性,我们通过get和set访问器进行访问和设置,用来保证数据的安全。属性访问器分为三种:
(1)只写属性:只包含set访问器;
(2)只读属性:只包含get访问器;
(3)读写属性:同时包含get和set。
例如:我们先定义一个私有字段,然后讲这个字段封装成属性:
private string _name;
public string Name
{
get{return _name;}
set{_name = value;}
}
自动属性的快捷键是prop + tab + tab,但是它只适用于不对字段进行逻辑验证的操作。
封装的好处:
(1)保证数据的安全性;
(2)提供清晰的对外接口;
(3)类内部可以实现任意修改,不影响其他类。
二、深入C#数据类型
Java和C#的数据类型非常相似,描述如下:
常用数据类型 | Java | C# |
---|---|---|
整型 | int | int |
浮点型 | float | float |
双精度型 | double | double |
字符串 | String | string |
布尔型 | boolean | bool |
枚举类型 | enum | enum |
1、值类型
值类型数据所在的内存区域为栈,只要在代码中修改它,就会在它的内存区域内保存这个值,值类型主要包括基本数据类型和枚举类型等。赋值操作传递的是变量的值,改变一个变量的值不会影响另一个变量的值。
2、引用类型
它源于System.Object家族,在C#中它主要包括数组、类和接口等。对于引用类型,赋值是把原对象的引用传递给另一个引用,对数组而言,当一个数组引用赋值给另一个数组引用后,这两个引用指向同一个数组,也就是指向同一块存储区间。
3、细分值类型和引用类型
C#中包含的值类型和引用类型如下图:
4、结构
结构类似类,但它不能手写无参构造函数,结构里有多少个字段,定义构造函数时就要有多少个参数。
结构的语法:
访问修饰符 struct 结构名
{
//结构体
}
结构的特点:
(1)结构中可以有字段、也可以有方法;
(2)定义时,结构中的字段不能被赋初值;
(3)可以不用new,直接定义结构的对象,但直接调用属性会报语法错误;
(4)声明结构的对象后,必须给结构的成员赋初值,结构在使用的时候,要给所有字段赋值。
5、装修和拆箱
值类型和引用类型也是可以相互转换的,将值类型转换为引用类型称为装箱,反之称为拆箱。
6、不同类型的参数传递
参数传递主要有三种:
(1)值传递:形参所做改变对实参没有影响;
(2)引用传递:当形参地址没有改变时,形参的值的改变对实参有影响;
(3)地址传递(ref):使用ref方式传递,形参所做改变对实参有影响。
注意:调用地址传递时,实参、形参的变量名前必须加上ref。
三、使用集合组织相关数据
集合主要分为了泛型集合和非泛型集合,它们的区别就是前者限定了数据类型,后者没有限定数据类型,接下来我们就来了解一下非泛型:ArryList、Hashtable和泛型集合:List、Dictionary。
1、ArrayList
ArrayList非常类似于数组,也有人称它为数组列表。它是动态可维护的,因此定义时可以指定容量也可以不指定。
ArrayList的常用属性及方法:
属性名称 | 说明 |
---|---|
Count | 获取 |
返回值类型 | 方法名称 | 说明 |
---|---|---|
int | Add(Object value) | 将对象添加到ArrayList的结尾处 |
void | RemoveAt(int index) | 移除ArrayList指定索引处的元素 |
void | Remove(Object value) | 从ArrayList中移除特定对象 |
void | Clear() | 从ArrayList中移除所有元素 |
遍历ArrayList的值有以下两种方法:
for(int i = 0; i < list.Count; i++)
{
Object obj = list[i];
}
foreach(T value in list)
{
Object obj = value;
}
2、List<T>
List<T>是一个泛型集合,它的语法是:
List<T> 对象名 = new List<T>();
<T>中的T可以对集合中的元素类型进行约束,它表明集合中是什么数据类型。List的属性、方法及遍历方式与上述ArrayList一致,所以现在来了解一下它们之间的区别:
3、Hashtable
Hashtable也属于System.Collections命名空间,它的每一个元素都是一个键/值对。
Hashtable的常用属性及方法:
属性名称 | 说明 |
---|---|
Count | 获取包含在Hashtable中键/值对的数目 |
Keys | 获取包含在Hashtable中键的集合 |
Values | 获取包含在Hashtable中值的集合 |
返回值类型 | 方法名称 | 说明 |
---|---|---|
void | Add(Object key,Object value) | j将带有指定键和值的元素添加到Hashtable中 |
void | Remove(Object key) | 从Hashtable中移除带有特定键的元素 |
void | Clear() | 从Hashtable中移除所有元素 |
遍历Hashtable也有两种方式,遍历所有的key为:
foreach(T key in ht.Keys)
{
Console.Write(key); //输出键
Console.Write(ht[key]); //输出值
}
遍历所有的value为:
foreach(T value in ht.Values)
{
Console.Write(value); //输出值
}
注意遍历key可以获取value,但是遍历value不能输出key。
4、Dictionary<K,V>
Dictionary存储数据的方式和Hashtable类似,它的语法为:
Dictionary<K,V> 对象名 = new Dictionary<K,V>();
Dictionary的属性、方法及遍历方式都与Hashtable相同,下面就来了解一下它们的区别吧:
5、泛型类
对于一些常常处理不同类型数据转换的类,可以使用泛型定义。它的语法是:
public class 类名<T>
{
//代码块
}
T指类型参数,代表具体的数据类型,可以是类类型,也可以是基本数据类型。
说到这里,总结起来泛型有以下几个优点:
(1)性能高;
(2)类型安全;
(3)实现代码的重用。
四、深入类的方法
1、构造函数
类的构造函数时类中的一种特殊方法,它的特点是:
1、方法名与类名相同;
2、没有返回值类型;
3、主要完成对象的初始化工作。
按显示方式分类,可分为:隐式构造函数和显式构造函数,隐式构造函数就是类自动带的无参构造函数;显式构造函数就是自定义的构造函数。
按参数类型分类可分为:无参构造函数和带参构造函数。
无参构造函数的语法是:
访问修饰符 类名()
{
//方法体
}
带参构造函数的语法是:
访问修饰符 类名(参数列表)
{
//方法体
}
2、方法重载
多个构造函数提供了多种实例化一个类的方式,这种方式就是方法重载。在面向对象语言中,方法重载允许我们在同一个类中定义多个方法名相同、参数列表(参数个数、参数类型)不同的方法。
方法重载的特点 :
(1)在同一个类中;
(2)方法名相同;
(3)方法参数个数不同或参数类型不同。
方法重载示例:
public static Main(string[] args)
{
Console.WriteLine(8);
Console.WriteLine(10.45);
Console.WriteLine("Hello");
Console.WriteLine(8,"Joe");
}
方法重载不仅仅是只针对于方法,构造函数重载是方法重载的一种特殊方式,例如:
public class Stu
{
public int num;
public stu()
{
num = 9;
}
public stu(int n)
{
num = n;
}
public stu(int n,string str)
{
num = n;
}
}
3、对象交互
在面向对象的世界里,一切皆为对象,对象与对象相互独立,互不干涉,但在一定外力的作用下,对象开始共同努力。
每个类都有自己的特性和功能,我们把它们封装为属性和方法,对象之间通过属性和方法进行交互,可以认为方法的参数及方法的返回值都是对象间相互传递的消息。
五、初识继承和多态
我们都知道类的三大特性有:封装、继承、多态。封装就是将内部材料隐藏起来,继承就是子承父,多态就是一种事物有多种形态。封装在之前就有详细介绍过了,那在这里就详细介绍一下继承和多态吧。
1、继承
当有两个类或多个类的代码可以提取公共部分的时候我们就可以运用到继承。一个父类可以有多个子类,但是一个子类只能有一个父类。父类又叫基类,子类又叫派生类。它们一旦产生继承关系,子类可以使用父类所有的非private成员。语法:
public class B:A
{
A:父类
B:子类
}
在其他类new对象时,只能调用父类的public成员,而子类能直接调用父类的public、protected成员。
(1)继承的构造函数
每一个子类的构造函数一定会调用父类的构造函数,在默认的情况下调用的是父类的无参构造函数。但是我们也可以显示的调用父类的构造函数,只需要在子类构造函数的形参的后面用base关键字即可。如:
public Stu(string name):base(){} //调用父类无参构造函数
public Stu(string name):base(name){} //调用父类带参构造函数
通常执行时,都是先执行父类构造函数,再执行子类构造函数。
我们在子类当中也可以通过base调用父类的成员,同时也可以通过this调用,两者在子类中具有相同的调用意义。
(2)继承的特点
继承最大的特点就是所有父类的引用都可以指向子类对象,如:
Person p = new Student(); //此处Person为父类,Student为子类,p只能调用父类公有成员,不能调用子类单独建立的成员
继承具有单根性和传递性的特性,单根性就是每个类只能有一个父类,传递性就是孙子可以有爷爷的基因,也就是说孙子类可以调用子类和父类的非private成员。
每个类如果没有显示定义,父类都会有一个默认父类Object,如果某个类不想被继承,在类的前面加sealed即可。
继承应用了里氏替换原则(LSP),所有引用父类的地方,都可以透明的使用子类对象。
(3)继承的优点
1、代码的重用性,子类拥有父类的属性和方法;
2、代码的可扩展性,子类可以拥有自己独有的属性和方法。
(4)继承的缺点
1、继承编程侵入式(父类约束了子类);
2、增加耦合性。
(5)is a 及as a 的应用
is a 是判断对象真正的数据类型,语法:引用名[对象名] is 数据类型,例如:
//Employee是父类,SE 和 PM是子类
List<Employee> emp = new List<Employee>();
emp.Add(new SE());
emp.Add(new PM());
foreach(Employee e in emp)
{
if(e is SE)
{
return true;
}
if(e is PM)
{
return false;
}
}
as a 是将对象强转为另外一个数据类型,语法:数据类型 变量 = 对象名 as 数据类型; 等价于:数据类型 变量 = (数据类型)对象名;
当父类引用指向子类成员时,如果我们想要调用子类独有的成员的方法:
1、is 判断数据类型,然后强转
2、重写
2、多态
多态就是一种事物有多种形态,每种形态都有不同的意义。多态有两种实现方式,分别是重载和重写,重载就是同一个类多态的实现,重写就是不同类多态的实现(两个类必须是继承关系)。
(1)重载
重载的特点:
1、在同一个类中;
2、具有相同的方法名;
3、具有不同的参数(个数、类型)。
重载根据参数的个数及类型调用。
重载可以是方法也可以是构造函数,例如:
//重载构造函数
public Stu(){}
public Stu(int age){}
public Stu(string name,string id){}
public Stu(string name,string id,int age){}
//重载方法
public void Show(){}
public void Show(int num){}
public void Show(int num,string str){}
public void Show(double dou,char ch,string str){}
(2)重写
重写就是重新写过,子类重写父类的方法。
重写的特点:
1、在不同的类中;
2、被重写的方法,方法名和参数必须和父类一模一样;
3、在父类中必须明确标注出可以被重写的方法,标注关键字:virtual、abstarct。
4、在子类的重写父类的方法必须用overrirde标注。
重写的实现方式有虚方法和抽象方法。
1、虚方法
(1)虚方法的特点:
1、在不同的类中;
2、有相同的方法名、参数;
3、在父类中声明虚方法要加virtual关键字;
4、在子类中用override声明重写虚方法。
注意:虚方法在父类中有方法体,子类也可以不实现虚方法。
虚方法的语法为:
//父类定义虚方法
访问修饰符 virtual 返回值类型 方法名()
{
//方法体
}
//子类定义虚方法
访问修饰符 override 返回值类型 方法名()
{
//方法体
}
2、抽象方法
(1)抽象方法特点:
1、在不同的类中;
2、有相同的方法名、参数;
3、没有方法体;
4、只能位于抽象类中;
5、子类必须实现父类的抽象方法(关键字也是override),除非子类是抽象类。
抽象方法的语法:
//父类
访问修饰符 abstract class 类名
{
访问修饰符 abstract 返回值类型 方法名(参数);
}
//子类
访问修饰符 abstract 返回值类型 方法名(参数){}
注意:抽象类不能new对象,不能用sealed和static修饰,抽象类中可以有抽象方法也可以有其他的普通方法。
3、虚方法和抽象方法的区别
(1)相同点:
1、它们都是在约束子类拥有某个动作,虚方法由父类实现约定,抽象方法由子类实现;
2、子类的关键字都是override。
(2)不同点:
1、定义关键字不同,虚方法是virtual,抽象方法是abstract;
2、在父类定义时,虚方法必须有方法体,抽象方法不能有方法体;
3、sealed类除外,虚方法可以位于任意类,抽象方法只能位于抽象类;
4、虚方法不强制要求子类必须实现,抽象方法要求子类必须实现,除非子类也是抽象类。
学到这里,类的三大特性也算是入了门了,要想充分了解它们,就需要不断的学习,慢慢的沉淀,好了,今天的分享就到这里啦,我们下期再见!
e),除非子类是抽象类。
抽象方法的语法:
//父类
访问修饰符 abstract class 类名
{
访问修饰符 abstract 返回值类型 方法名(参数);
}
//子类
访问修饰符 abstract 返回值类型 方法名(参数){}
注意:抽象类不能new对象,不能用sealed和static修饰,抽象类中可以有抽象方法也可以有其他的普通方法。
3、虚方法和抽象方法的区别
(1)相同点:
1、它们都是在约束子类拥有某个动作,虚方法由父类实现约定,抽象方法由子类实现;
2、子类的关键字都是override。
(2)不同点:
1、定义关键字不同,虚方法是virtual,抽象方法是abstract;
2、在父类定义时,虚方法必须有方法体,抽象方法不能有方法体;
3、sealed类除外,虚方法可以位于任意类,抽象方法只能位于抽象类;
4、虚方法不强制要求子类必须实现,抽象方法要求子类必须实现,除非子类也是抽象类。
学到这里,类的三大特性也算是入了门了,要想充分了解它们,就需要不断的学习,慢慢的沉淀,好了,今天的分享就到这里啦,我们下期再见!