.NET框架
1、简介
由微软公司由2000年发布,.NET框架是开发.NET应用程序的核心基础,.NET框架经历了1.0、1.1、2.0、3.0、3.5、4.0、4.5七个版本,我这里介绍的是4.0以上的版本。
2、功能性
.NET框架提供了一个面向对象的编程环境,完全支持面向对象编程。.NET框架提高了软件的可复用性、可扩展性、可维护性和灵活性。对Web应用的强大支持。
3、结构组成
.NET框架运行在操作系统之上,是.NET最基础的框架,主要包含公共语言运行时(CLR)和框架类库(FCL),并且支持多种开发语言。
3.1、CLR
CLR可以看成一个在执行是管理代码的代理,管理代码是CLR的基本功能,能够被其管理的代码称为托管代码,反之称为非托管代码。CLR包含两个重要的组成部分:CLS(公共语言规范)和CTS(通用类型系统)。
3.1.1、.NET的编译技术
所有在.NET编写的代码都会通过他们各自的编译器编译成MSIL:俗称中间语言,可被平台(操作系统)识别,从而进行编译。这种编译方法不但实现了代码托管,还提高了程序的运行效率。
3.1.2、CLS(公共语言规范)
编程语言区别不仅在于类型,语法或者语言规范都有很大的区别,CLS限制了不同点引发的互操性问题。是一种最低的语言标准。
3.1.3、CTS(通用类型系统)
用来解决不同语言数据类型的不同的问题。
3.2、框架类库
FCL提供了对系统功能的调用,是建立.NET应用程序、组件和控件的基础。在使用FCL时会导入自己所需要的命名空间
C#语言的基本
一、C#的面向对象
1、类和对象
类和对象有着本质的区别,类定义了一组概念的模型(抽象的),而对象是真正的实体。类是对象的抽象,对象是类的实例
2、类的成员
C#中类有三个成员,分别为:字段、属性和方法
字段:字段是类的私有成员变量
属性:就是私有字段进行公有化
- 只写属性:只包含set访问器
- 只读属性:只包含get访问器
- 读写属性:同时包含set访问器和get访问器
private string _name; //私有字段
public string Name
{
get {return _name;} //获取值
set {_name=value;} //赋值
}
方法:
语法:
访问修饰符 返回值类型 方法名(有参/无参)
{
return 返回值;
}
有参方法的参数传递:
- 值传递:在方法中对参数值的更改在调用后不能保留;
- 引用传递:地址不变,可以保留对参数值的更改
- 使用ref传递:可以保留对参数值的更改;
总结:
- 使用值方式(不用ref修饰)传递值类型参数时,参数在方法中的修改不会保留;
- 使用值方式(不用ref修饰)传递引用类型参数时,除了new之外,参数在方法中的修改会保留;
- 使用引用方式(用ref修饰)传递值类型或引用类型参数时,参数在方法中的修改都会保留;
3、深入C#的数据类型
3.1、结构
关键字:struct。
1、结构的语法:
访问修饰符 struct 结构名
{
//结构体
}
2、结构的定义有以下的特点
- 结构中可以有字段,也可以有方法
- 定义时,结构中的字段不能被赋初始值
3、在使用结构时要注意以下几个方面
- 可以不用new,直接定义结构的对象即可
- 声明结构后,必须给结构的成员赋初值
- 并且不能手写无参构造函数
4、结构是值类型,用的越多系统的存储空间消耗的也越多
3.2、值类型
值类型源于System.ValueType命名空间,值类型数据所在的区域称为 “栈”,只要修改它,就会在它的内存区域内保存这个值,值类型主要包括的基本数据类型 :
int, long, float, double, char, bool, bool,enum, struct
3.3、引用类型
引用类型源于System.Object命名空间,在C#中引用类型主要包括 :
类(Class),数组,集合,接口
4、装箱和拆箱
我们说数据类型按照储存方式可以分为值类型和引用类型,两者可以互相转换。
- 装箱:将值类型转换为引用类型的过程叫装箱。
- 拆箱:将引用类型转换为值类型叫拆箱。
static void Main(string [] args)
{
int i=123;
object o=i; //装箱
int j=(int)o; //拆箱
}
二、集合
集合的概念:大小可变的动态数组。
以下介绍的都是集合。
泛型的概念
泛型限定了数据类型,非泛型没有限定数据类型
1、非泛型集合
1.1、ArrayList
ArrayList称为数组列表,类似于数组,ArrayList可以动态维护,一般数组的长度都是固定的,而ArrayList的容量可以根据需要自动扩充,它的索引会根据程序的扩展而重新分配调整.
ArrayList类属于System.Collections命名空间,这个命名空间包含接口和类;
ArrayList常用的方法和属性:
属性名称 | 说明 | |
---|---|---|
Count | 获取ArrayList中实际包含的元素数 | |
返回值类型 | 方法名称 | 说明 |
int | Add(Object value) | 将对象添加到ArrayList的结尾处 |
void | RemoveAt(int index) | 移除ArrayList指定的索引元素 |
void | Remove(Object value) | 从ArrayList中移除特定元素 |
void | Clear() | 移除所有元素 |
遍历ArrayList中的元素
ArrayList array = new ArrayList()
foreach(Object item in array)
{
Console.WirteLine(item);
}
1.2、Hashtable
C#提供了一种称为Hashtable的数据结构,通常称为哈希表,Hashtable的结构是通过键(Key)和值(Value)来组织的
Hashtable也属于System.Collections命名空间,它的每一个元素都是一个键/值对应的;
Hashtable的常用属性和方法:
属性名称 | 说明 | |
---|---|---|
Count | 获取包含Hashtable中键/值对的数目 | |
Keys | 获取包含在Hashtable中键的集合 | |
Values | 获取包含在Hashtable中值的集合 | |
返回值类型 | 方法名称 | 说明 |
void | Add(Object key,Object value) | 带有指定键和值的元素添加到Hashtable |
void | Remove(Object key) | 从Hashtable中移除带有特定键的元素 |
void | Clear() | 从Hashtable中移除所有元素 |
遍历Hashtable中的元素
Hashtable<K,V> array = new Hashtable<K,V>()
//遍历所有的key
foreach(Object item in array.Keys)
{
Console.WirteLine(item);
}
//遍历所有的Value
foreach(Object item in array.Values)
{
Console.WirteLine(item);
}
2、泛型集合
泛型引入了一个概念:类型参数。通过使用类型参数(T),减少了运行时强制转换或装箱操作的风险,比较经典的泛型集合是List< T >和Dictionary<K,V>。
2.1、 List< T >
List<T> 对象名=new List<T>();
"< T >"中的T可以对集合中的元素类型进行约束,T表明集合中管理的元素类型;
List< T >的使用方法和ArrayList类似,只是List< T >无须类型转换;
List与ArrayList的区别:
List< T > | ArrayList | |
---|---|---|
不同点 | 对所保存元素进行类型约束 | 可以增加任何类型 |
添加/读取值类型元素无须拆箱和装箱 | 添加/读取值类型元素需要拆箱和装箱 | |
相同点 | 通过索引访问集合中的元素 | |
添加元素方法相同 | ||
删除元素方法相同 |
2.2、Dictionary<K,V>
Dictionary<K,V> 对象名=new Dictionary<K,V>();
说明:<K,V>中K表示集合中Key的类型,V表示Value的类型
例如:
Dictionary<string,SE> eng=new Dictionary<string,SE>();
eng集合的Key类型是string型,Value是SE类型;
Dictionary<K,V>和Hashtable的对比:
Dictionary<K,V> | Hashtable | |
---|---|---|
不同点 | 对保存元素进行类型约束 | 可以增加任何类型 |
添加/读取值类型元素无须拆箱和装箱 | 添加/读取值类型元素需要拆箱和装箱 | |
相同点 | 通过Key获取Value | |
添加元素方法相同 | ||
删除元素方法相同 | ||
遍历方法相同 |
3、泛型类
使用泛型类,可以封装不是特定于具体数据类型的操作。定义泛型类的过程,与定义一个类相似,不同之处在于,尖括号里定义了类型参数;
public class 类名<T>
{
//.....
}
T指类型参数,代表具体的数据类型,可以是引用类型,也可以是基本数据类型。
泛型有以下优点:
- 性能高,不需要进行繁琐的装箱和拆箱的操作
- 类型安全,限定了数据类型的存储
- 实现代码的重用性
三、深入类的方法
构造函数
构造函数的用处:用于new对象、可以给成员变量赋值
兼职:用于给成员变量赋值
构造函数具有以下特点:
- 方法名和类名相同
- 没有返回值类型
- 主要完成对象的初始化工作
1、无参构造函数
定义无参构造函数的语法:
访问修饰符 类名()
{
//方法体
}
2、带参构造函数
一般来讲,给方法设置参数可以调整方法的行为,使方法多样化。构造函数的参数列表一般用于给属性赋值。
定义有参构造函数的语法如下:
访问修饰符 类名(参数列表)
{
//方法体
}
在调用带参函数时需要注意的几点:
- 参数的个数要对应
- 参数的数据类型要一一对应;
在默认的情况下,系统会给类分配一个隐式无参构造函数,并且没有方法体,手写了构造函数之后,隐式无参构造函数会消失
构造函数在每次实例化类的时候通过new关键字调用
四、类的三大特性
1、封装
封装:使内部结构私有化
封装的魅力:
- 保证数据的安全性
- 提供清晰的对外接口
- 类内部实现可以任意修改,不影响其他类
将字段封装为属性是封装的一种方式,类的私有方法也是一种封装。
2、继承
子类具有父类的属性和方法,被继承的类称为父类或基类,继承其他类的被称为子类或者派生类
继承是使用已经存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用已存在的类的功能
在有继承关系的两个类中,子类不仅具有自己独有的成员,还具有父类的非private成员。
2.1、base关键字
创建子类时会先调用父类的构造函数,默认会调用父类的无参构造函数。
使用base关键字就可以显示的调用父类的构造函数。只要在子类的构造函数后添加":base(参数列表)",就可以指定子类调用父类的哪一个构造函数了。
2.2、继承的特性:
传递性:
继承具有传递性,就相当于遗传,一个类可以有很多代。
单根性:
一个子类只能存在一个父类,这就是继承的单根性。
C#中还有一个特殊的关键字:sealed,使用它修饰的类不能够被继承,我们称这种类为继承类。
2.3、is a 和as a
is a:
用来判断对象是否属于给定的类型,是就返回true,不是就返回false。例如:
string str = "";
if(str is string) //会返回true
{
Console.WriteLine("str是string类型的") //会输出
}
else
{
Console.WriteLine("str不是string类型的") //不会输出
}
as a:
用来强制转换数据类型,转换失败会返回null,并不会报异常。使用的时候需要注意,用法与is a相仿。
2.4、里氏替换原则
概念:里氏替换原则是软件设计应该遵守的重要原则之一,指所有引用父类的地方,都可以透明的使用子类对象
通过is a和as a可以体现里氏替换原则。
2.5、继承的价值
1、继承模拟了现实世界的关系 ,符合面向对象的思想
2、继承提高了代码的重用性,子类拥有父类的属性和方法
3、提高了代码的可扩展性,子类形似父类,也异于父类,保留自我个性。
3、多态
一个对象的多种形态,实现方式:重载+重写
3.1、重载
在面向对象的语言中,允许我们在同一个类中定义多个方法名相同,参数列表(参数个数,参数类型)不同的方法,称为方法重载。调用时会根据实际传入参数的形式,选择与其匹配的方法执行。
重载的特点:
- 在同一个类中;
- 方法名相同;
- 方法参数类型不同或者参数个数不同;
注意:方法名以及参数列表相同的方法,仅是返回值类型不同,不能称为方法重载。
方法重载示例:
public void Show()
{
Console.WriteLine("Hello World");
}
public void Show(string name)
{
Console.WriteLine("我的名字是:{0}"+name)
}
以上示例就是方法重载的使用
3.2、重写
特点:
不同的类中、相同的方法名、相同的参数、在有继承关系的两个类中
实现方式:
3.2.1、虚方法
父类的方法使用virtual关键字修饰,语法如下:
访问修饰符 virtual 返回值类型 方法名()
{
//方法体
}
子类重写的方法使用override关键字修饰,语法如下:
访问修饰符 override 返回值类型 方法名()
{
//方法体
}
虚方法不要求子类必须重写父类的方法,在父类中可以给出虚方法的默认实现。如果子类不重写父类的虚方法,依然执行父类的默认实现。如果子类重写了,执行重写后的方法。
3.2.2、抽象方法
父类的方法使用abstract关键字修饰,语法如下:
访问修饰符 abstract 返回值类型 方法名();
子类重写的方法使用override关键字修饰,语法如下:
访问修饰符 override 返回值类型 方法名()
{
//方法体
}
抽象方法必须位于抽象类中,并且没有方法体。规定子类必须重写父类的抽象方法(除非子类也是抽象类)。
**虚方法和抽象方法的区别:**如下表所示
虚方法 | 抽象方法 |
---|---|
用virtual修饰 | 用abstract修饰 |
要有方法体,即使是一个分号 | 不允许有方法体 |
可以被子类override | 必须被子类override |
除了密封类外都可以定义 | 只能在抽象类中定义 |
3.2.3、抽象类
语法如下:
访问修饰符 abstract class 类名{}
**注意:**抽象类不能被实例化,并且不能是密封的或者静态的。
4、总结
封装:保证对象自身数据的完整性和安全性
继承:建立类之间的关系,实现代码复用,方便系统的扩展
多态:相同的方法调用可实现不同的实现方式