深入.NET平台和C#编程
一. netFrameWork框架
运行在操作系统上,是.net的基础环境它由两部分组成,分别是CLR,FCL
1、CLR:公共语言运行时
运行环境
基本规范:
.1、CTS:规范类型(type)
C#:int--->int32
java:int/Integer-->int32
Convert.ToInt32()
.2、CLS:规范语法(language)
在C#和java表示代码块:{}
python代码块:通过缩进
C#Main/Java-main语法
.3、MSIL:中间语言
java/C#数组:
2、FCL:框架类库
表示一部分已经被封装好的功能的集合
用法:引用命名空间
3、面向对象的回顾
定义: 类是对象的抽象,对象是类的具体
类的三大特性:
(1)类的特性:封装:将一些特性私有化,将底层(实现过程)藏起来(实现方案:将内容用方法包装)
private int age;
public int Age
{
get{}
set
{
if(age > 10){有错}
}
}
(2) 继承:子承父业
(3)多态:一个事物的多种形态
定义类:
public class 类名
{
//字段私有
//属性:get[只读]、set[只写]
//方法
}
public class 示例
{
private string _name;
public string Name
{
get { return Name; }
set { _name = value; }
}
}
class Student
{
public int ID;
public string name;
public int age;
public string address;
}
static void Main(string[] args)
{
Student stu = new Student();
Console.Write("请输入编号:");
stu.ID = Convert.ToInt32(Console.ReadLine());
Console.Write("请输入姓名:");
stu.name= Console.ReadLine();
Console.Write("请输入年龄:");
stu.age = Convert.ToInt32(Console.ReadLine());
while (stu.age <= 18)
{
Console.WriteLine("学员年龄必须大于等于18岁");
Console.Write("请重新输入年龄:");
stu.age = Convert.ToInt32(Console.ReadLine());
}
Console.Write("我的家庭住址为:");
stu.address = Console.ReadLine();
string XxI = string.Format("我的编号为{0},姓名为{1},年龄为{2},家庭住址为{3}",
stu.D,stu.name,stu.age,stu.address);
Console.WriteLine(XxI);
Console.ReadLine();
}
类成员:属性字段,方法
深入C#数据类型
C#数据类型分为两种,有基础数据类型还有引用数据类型今天我要说的是一种我新认识的的数据类型(结构)Struct,它属于哪一种数据类型嘞,小的等下借给大家解答
下面是基础的数据类型表格
常用数据类型 | Java | C# | 举例 |
---|---|---|---|
整型 | int | int | 年龄 |
浮点型 | float | float | 成绩 |
双精度型 | double | double | 圆周率 |
字符型 | string | string | 家庭住址 |
布尔型 | boolea | bool | 是否为少数民族 |
枚举类型 | enum | enum | 颜色 |
值类型
值类型源于System.ValueType家族,每个值类型的对象都有一个独立的内存区域用于保存自己的值,值类型数据所在的内存区域称为栈(stack)。只要在代码中修改它,就会在他的区域内保存这个值。值类型主要包括基本数据类型(如int,float,double)和枚举类型等。
引用类型
引用类型源于System.Object家族,在C#中引用类型主要包括数组,类和接口。
结构
结构的定义
访问修饰符 struct 结构名
{
//结构体
}
结构的定义有以下特点
- 结构中可以有字段,也可以有方法。
- 定义时,结构中的字段不能被赋初始值。
- 使用关键字Struct字段不能赋初始值,不能手写无参构造函数。
结构的使用
结构的构成和类相似。在使用结构时,要注意一下几个方面
- 可以不用New,直接定义结构的对象即可。
- 声明结构的对象后,必须给结构的成员赋初值。
- 结构里面有多少个字段,构造函数里面就要有多少个参数。
结构的使用经验
既然结构和类非常相似,是不是所偶的类都可以用结构来实现呢?结构是值类型,声明结构变量就存储一个结构的新副本,既系统要开辟一块新的存储空间,因此结构用得越多所消耗的存储空间也越多。
装修和拆箱
我们说数据类型按照存储方式可以分为值类型和引用类型,两者任然可以相互转换,将值类型转换为引用类型的过程称为装箱,反之称为拆箱。
static void Main(string[] args)
{
int i = 123;
object o = i ; //装箱
int j = (int)o; //拆箱
}
先将值类型 i 进行装箱,然后把转换后的引用类型o 进行拆箱处理。切记拆箱时,被转换引用类型的数值必须能够转换为目标值类型
注意
在实际的开发中,应该尽量减少不必要的装箱和拆箱,应为二者的存储方式不同,转换时性能损失较大。在后面的章节中我们将讲解如何利用泛型集合减少装箱和拆箱。
不同类型的参数传递
为方法传递参数,我学习了值传递和地址传递(ref)两种参数传递方式。
- 使用值传递,在方法中对参数值的更改在在调用后不能保留。
- 使用ref方式产地,可以保留对参数值的更改
那么当传递至类型和引用类型参数时,会对参数本身产生什么影响呢?
值方式参数传递
在值方式参数传递时,参数可以是引用类型,也可以是值类型。
使用引用类型作为参数:当引用变量发生改变时,参数发生了变化。因此,当类作为参数传递时,参数被修改,类成员的值也会被修改。其他引用类型的参数也是如此。
使用值类型作为参数:以值类型作为参数精选值方式产地参数是,不能改变值类型参数的值。
引用方式参数传递
在引用方式参数传递时,参数同样可以是引用类型,也可以时值类型。
无论引用方式传递引用类型,还是传递值类型,程序运行结果都一样:员工的人气值发生了改变,也就是说,用ref方式产地的两种参数形式没有区别,都会保存方法中的修改。
小结
使用值类型(不用ref修饰) 传递值类型参数时,参数在方法中的修改不会保存;
使用值类型(不用ref修饰) 传递引用类型参数时,参数在方法中的修改不会保存;
使用引用方式(用ref修饰) 传递值类型或引用类型参数时,参数在方法中的修改都会保留;
三.使用集合组织相关信息
基本定义:
1、集合:保存一组大小不固定的值
2、类似数组:
3、泛型跟非泛型:
泛型:限定了数据类型
非泛型:没有限定数类型
ArrayList
ArrayList:没有限定数据类型—>涉及到频繁的拆箱装箱,类型转换
1、创建对象
ArrayList list = new ArrayList();
2、属性:
Count–》得到长度
3、方法:
Add(Object value)–>添加
RemoveAt(int index)–>移除的是下标
Remove(Object value)—>移除的是值
Clear()—>清空所有的
[int index]–>1、获取值;2、赋值【注意:下标一定是已经存在的】
4、遍历
for
for(int i = 0; i < list.Count;i ++)
{
Object obj = list[i];
Console.WriteLine(obj );
}
foreach
foreach(Object value in list)
{
Console.WriteLine(value );
}
List
List:限定了数据类型
1、创建对象
List list = new List();
T:任意数据类型
List可以实现ArrayList的效果–》List也可以保存任意值
List
List list = new List(); //不放T数据类型,error,编译报错
2、属性:
Count–》得到长度
3、方法:
Add(Object value)–>添加
RemoveAt(int index)–>移除的是下标
Remove(Object value)—>移除的是值
Clear()—>清空所有的
[int index]–>1、获取值;2、赋值【注意:下标一定是已经存在的】
4、遍历:
for:
for(int i = 0; i < list.Count; i++)
{
list[i]
}
foreach
foreach(T value in list)
{
value
}
Hashtable
1、创建对象
Hashtable ht = new Hashtable();
2、属性
Count–》得到长度
Keys—>得到当前Hashtable里面所有的键
Values–>得到当前hashtabale里面所有的值
3、方法
Add(Object key, Object value)
Remove(Object key)–>根据key移除
Clear()清空
5、遍历:
1、遍历所有key
foreach(Object key in ht.Keys)
{
key + ht[key]
}
2、遍历所有的value
foreach(Object value in ht.Values)
{
value
}
4、key是唯一
Dictionary
1、创建对象
Dictionary<Tkey, Tvalue> dic = new Dictionary<TKey, Tvalue>();
2、属性
Count–》得到长度
Keys—>得到当前Hashtable里面所有的键
Values–>得到当前hashtabale里面所有的值
3、方法
Add(Object key, Object value)
Remove(Object key)–>根据key移除
Clear()清空
ContainsKey(TKey key);–》判断key是否已经存在,存在返回true
5、遍历:
1、遍历所有key
foreach(T key in ht.Keys)
{
key + ht[key]
}
2、遍历所有的value
foreach(T value in ht.Values)
{
value
}
4、key是唯一
3、null不能作为key,运行的时候会报错
示例:
//使用Dictionary字典保存套餐集合
public Dictionary<string, HealthCheckSet> HealthSet = new Dictionary<string, HealthCheckSet>();
#region 创建所有检查项目,并保存在AllItems集合中
public void AllItemsd()
{
height = new HealthCheckItem("身高","用于检查身高",5);
weight = new HealthCheckItem("体重","用于检查体重",5);
Gang = new HealthCheckItem("肝","用于检查肝功能",50);
B超 = new HealthCheckItem("B超","用于检查B超",30);
ekg = new HealthCheckItem("心电图", "用于检查心电图", 50);
bloodPressure = new HealthCheckItem("血压", "用于检查血压", 20);
bloodTest = new HealthCheckItem("血常规","用于检查血常规", 20);
AllItems.Add(height);
AllItems.Add(weight);
AllItems.Add(Gang);
AllItems.Add(B超);
AllItems.Add(ekg);
AllItems.Add(bloodPressure);
AllItems.Add(bloodTest);
}
#endregion
#region 创建一组默认套餐设置
private void InerSet()
{
//创建1种默认套餐对象
items = new List<HealthCheckItem>();
items.Add(height);
items.Add(weight);
items.Add(B超);
set = new HealthCheckSet("入学体检", items);
//计算套餐价格
set.CalcPrice();
this.HealthSet.Add("入学体检", set);
}
#endregion
自定义泛型:
作用:
保证类里面的变量数据类型更加灵活
语法:
public class 类名
{
}
深入类的方法
构造函数
类的构造函数是类中的一种特殊方法,它具有以下特点。
- 方法名和类名相同
- 没有返回值类型
- 主要完成对象的初始化工作,还有一个兼职给成员变量赋值
相信大家可能都有一个疑问,构造函数没有返回值类型,是不是可以定义为Void?
解答:由于void修饰的方法表示返回值类型为空,并不代表没有返回值类型,所以不能将构造函数定义为Void.
根据普遍的经验,我们在进行开发时,一般不在构造函数中进行对类的实例初始化以外的事情,不要尝试显示地调用构造函数。
构造函数分为三种,接下来小的为大家一一介绍:
无参构造函数
在默认的情况下,系统将会给类分配一个无参构造函数,并且没有方法体。我们也可以自定义一个午餐鼓噪函数,在无参构造函数的方法体中对类的属性进行赋值。无参构造函数的语法如下:
访问修饰符 类名()
{
//方法体
}
在午餐构造函数中给属性赋予默认值有一个明显的缺点,就是对象实例化的属性值是固定的,为满足对象多样化的需求,不得不修改代码重新给属性赋值。有什么方法可以改变这种现象呢?
一般来讲,给方法设置参数可以调整方法的行为,时方法功能多样化。例如public int Add(int a,int b){}这个方法,可以接收两个整型的参数,因此,能给它传递任何整型值以满足不同的需求。同样,构造函数也可以接收参数,用这些参数给属性赋值,这就是我说的狗咱函数的兼职。
带参构造函数
访问修饰符 类名(参数列表)
{
//方法体
}
注意:调用带参构造函数一定要使用传入的参数和参数列表相对应
构造函数在每此实例类时通过new关键字调用。
隐式构造函数
当不给类编写构造函数时,系统将自动给类分配一个无参构造函数,称为隐式构造函数。C#有一个规定,一旦类有了构造函数,将不再自动分配构造函数。所以写了带参构造函数后必须要自己写一个无参构造函数否则不能调用无参构造函数。
深入构造函数
1、语法和作用
访问修饰符 类名(){}
注意:
1、类似方法,只是少了一个返回值
2、方法名有要求:跟类名一致
3、构造函数也是会被重载
用来new对象,兼职:给成员变量赋值(作用)
继承
人类是一个类但不过分很多的工作很显然从图可以看出两个类有完全相同的属性:年龄(Age),性别(Gender),编号(ID)和姓名(Name),也就是说,两个类中描述这些相同属性的代码也是相同的。如果扩展这个程序,加入CEO,CTO,CFO之类的角色,他们必然也有年龄,性别,编号,和姓名这些属性,编码是因为岗位不同会编写大量关于这些属性的重复代码,造成冗余。随着系统规模的扩大,冗余越来越多,从商业开发的角度考虑,这样冗余的代码是不可以容忍的。
如何避免这种冗余,把冗余代码集中起来重复使用呢? 那么就需要用类的三大特性之一继承:子类继承父类
1、继承
继承的语法:
概念:描述两个类之间的关系
父类/基类:被继承的类
子类/派生类:继承的类
- 通过new对象调用类里面的成员,只有public可以直接调用
- 一旦产生继承关系,子类里面可以直接使用父类里面所有【非private】成员
- 一旦继承了,new子类对象时,父类里面的成员的使用规则跟本类成员的使用规则是一样
默认访问修饰符:
类的默认访问修饰符:internal
类的成员的默认访问修饰符:private
- 1、每一个子类的构造函数一定会调用父类的构造函数
- 2、默认的情况下:调用的是父类的无参构造函数也可以显示调用无参构造函数–》在形参的结束小括号后面::base()
- 3、也可以显示的调用父类的构造函数:
多态
前提两个类必须是继承关系
实现多态有两种方法:
第一种是重载,第二种是重写
第一种重载我就不再多说了上面深入类的方法里面详细介绍了
现在我给大家介绍第二种重写:
虚方法
- 在不同的类中
- 相同的方法名,相同的参数列表
- 在父类中声明当前方法是要被子类重写:virtual
- 在父类中,重写方法
- 在子类中可以不重写虚方法
注意
- 虚方法在父类中是有方法体的
- 子类可以不实线虚方法
抽象方法
特点
- 在不同类中
- 相同的方法名和参数列表
- 没有方法体
- 只能位于抽象类中
- 父类里面的抽象方法,子类必须实现
定义抽象方法
访问修饰符 abstract 返回值类型 方法名(参数列表);
定义抽象类
访问修饰符 abstract class 类名{}
特点不能New对象
抽象类不能用Static和sealed修饰