C#程序设计.唐大仕.13.深入理解C#语言

[TOC]

深入理解 C# 语言

1. 类型与转换

  • 数据类型
值类型 引用类型
存储位置
默认值 Zeored null
等号操作 所有值复制 指向同一个对象
  • 值类型的转换
    • 数字类型之间可以互相转化
    • 隐式转换
    • 显式转换(强制类型转换)
    • 整型提升
  • 枚举类型与数字类型之间可以显式转换(强制类型转换
  • 结构类型之间不能转换
  • 引用类型转换
    • 子类转父类(隐式)
    • 父类转子类(显式)
      • 可能成功、可能异常
  • as
    • 失败则等于 null(而不是抛异常)
  • 引用类型与值类型的转换
    • boxing、unboxing
      • 存储位置出现改变

2. 变量及其传递

域变量及局部变量

  • 类 static 变量
    • 相当于类中的全局变量
  • 域变量
    • 相当于对象中的变量
  • 局部变量
    • 在函数体及其 {} 中,在栈中分配,自动消失
    • 域变量自动有初值,局部变量则不

按值传送的参数

  • 按值传送
    • 要注意值类型与引用类型

ref 参数及 out 参数

  • 效果相当于 C++ 的引用
  • ref 参数在传之间必须先赋值
  • out 参数在函数中必须赋值后才能返回
  • 表达式及对象的属性不能作 ref 及 out 参数

params 参数

  • 数组参数(相当于VB的可变参数)
  • 参数必须放在最后
  • 调用:
    • 可用数组,也可用多个参数
1
2
3
4
5
6
7
8
// 定义
double Multi(params double[] nums);
// 调用
Multi();
Multi(27);
Multi(3.14, 0.9, 0.9);
Multi(1,2,3,4,5);
Multi(new double[] {1,2,3,4,5})

默认参数

1
2
3
void ZoomIn( Point p, double k = 1){
// ...
}

3. 多态与虚方法调用

  • 多态(Polymorphism)

多态定义

  • 在面向对象的系统中,多态性是一个非常重要的概念,它允许客户对一个对象进行操作,由对象来完成一系列的动作,具体实现哪个动作、如何实现由系统负责解释
  • 在C#中,多态性的定义是,同一操作作用于不同的类的实例,不同的类将进行不同的解释,最后产生不同的执行结果
    • C#支持两种类型的多态性。

两种多态

  • 编译时的多态性
    • 编译时的多态是通过重载来实现的
    • 对于非虚的成员来说,系统在编译时,根据传递的参数、返回的类型等信息决定实现何种操作
  • 运行时的多态性
    • 运行时的多态性是指直到系统运行时,才根据实际情况决定实现何种操作
    • C#中,运行时的多态性通过虚成员实现
  • 好处
    • 编译时的多态性提供了运行速度快的特点
    • 而运行时的多态性则带来了高度灵活和抽象的特点

上溯造型与虚方法调用

1
2
3
4
5
6
7
8
9
10
11
class Shape {
public virtual void draw() {
Console.WriteLine("Shape Drawing");
}
}

class Circle : Shape {
public override void draw() {
Console.WriteLine("Draw Circle");
}
}
  • virtual、override

语法

  • 必须有 virtualabstractoverride 所修饰
  • 虚方法不能省略访问控制符
    • 不能是 private 的,不能是 static 的
    • 因为它们应该可以被子类所覆盖。
  • 子类中要覆盖父类的虚方法,必须用 override
    • 否则认为是新(new)的一个方法,并隐藏了父类的方法,不会实行虚方法调用
    • 覆盖和被覆盖的方法必须有相同的可访问性和相同的返回类型
  • 重要例子

虚方法与非虚方法

  • 虚方法调用的方法是由对象实例的类型所决定
  • 非虚方法调用的方法是由所声明的对象变量来决定的

最可派生的方法

  • 继承链中既有 override 也有 new
  • 示例

4. 动态类型确定

is 运算符

  • 用于判断运行时对象的类型
1
2
3
if(obj is TypeA) {
// ...
}

== 和 !=

  • 值类型相等
  • 引用类型的相等
    • 是判断是否是同一对象
    • 除非重载了 == 及 != 操作
    • 对于 string 等类型,已经进行了重载
    • 对于两个 boxing 的对象,== 总是 false

得到类型信息

  • typeof 运算符
    • typeof(System.Console)
  • 对象.GetType()
  • Type.GetType(string 类名)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class TypeGetType {
static void Main() {
int x = 1;
double d = 1.0;
Type[] t = {
typeof(int),
typeof(System.Int32),
typeof(string),
typeof(double[]),
x.GetType(),
(x+d).GetType(),
Type.GetType( "System.Console" ),
};
}
}
  • 获得这个类型的其他元信息

反射

  • 可以从 exe 文件中获取信息

5. 对象构造与析构

构造方法

  • 构造方法的初始化部分,使用 thisbase
    • 调用本类或父类的构造方法
    • 不用 this 且不用 base,则会自动认为 base()
      • 这样的写法要求基类必须有默认构造方法

域的初始化

  • 域的初始化中不能引用 this
  • 在 base 被调用之前不能引用 this
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class A{
public A(){}
public A(int i){}
}

class B : A {
int x = 1;
int M() {
return 1;
}
int y = x+M(); //Error
B():base(x) {} //Error
public static void Main(){}
}

// t.cs(12,13): error CS0236: 字段初始值设定项无法引用非静态字段、方法或属性“B.x”
// t.cs(12,15): error CS0236: 字段初始值设定项无法引用非静态字段、方法或属性“B.M()”
// t.cs(13,14): error CS0120: 对象引用对于非静态的字段、方法或属性“B.x”是必需的

构造顺序

  • 执行过程(Java 2/3 相反)
    • 若有 this,转向之
    • 执行域的初始化
    • 转到 base
    • 执行方法体
  • 应避免在构造方法中调用任何虚方法
  • 示例

静态构造方法

  • 静态构造方法总是在该类的所有静态域初始化之后执行
  • 静态构造方法总是在该类被使用(如访问静态域、生成实例)之前完成
  • 静态构造方法最多被执行一次
  • 静态构造方法的执行顺序的不确定性,所以在使用构造方法时应谨慎
  • 应尽量避免在静态初始化或静态域中出现循环引用的情况
1
2
3
4
5
6
7
8
9
using System;
class B {
static int a = b + 1;
static int b = a + 1;
public static void Main() {
Console.WriteLine("a={0},b={1}",a,b);
}
}
// a=1,b=2

析构方法

  • ~类名(){}
    • 析构方法会自动调用父类的析构方法
  • 编译器生成的构造方法名字为 ctor()
  • 生成的析构方法名字为 Finalize()
  • 不能显式地调用析构方法

自动垃圾回收

  • 垃圾回收(garbage collection)
  • 自动回收
  • 强制回收
1
System.GC.Collect(); // 告诉系统建议回收

显式资源管理

  • 实现 IDisposable 接口
1
2
3
4
5
6
namespace System {
[System.Runtime.InteropServices.ComVisible(true)]
public interface IDisposable {
void Dispose();
}
}

using 语句

  • 如下两种方式等价
1
2
3
4
5
6
7
8
9
R r1 = new R();
try {
r1.F();
}
finally {
if (r1 != null) {
((IDisposable)r1).Dispose();
}
}
1
2
3
using (R r1 = new R()){
r1.F();
}

6. C# 语言新特性

  • 2.0 引入泛型
  • 3.0 引入Lambda及Linq
  • 4.0 引入动态特性dynamic
  • 5.0 引入并行及异步async/await及Task
  • 6.0 改进编译,属性初始化

2.0

  • 泛型 List<T>
  • 泛型 delegate
    • Predicate<T>
    • Comparison<T>
    • Converter<TInput,TOutput>
    • EventHandler<TEventArgs>
  • 匿名方法
    • delegate(参数) { 方法体 }

3.0

  • Linq 示例
  • 扩展方法,用于给一个类新添加方法
    • 牛逼啊,这个给控件扩展放啊实在太棒了,可惜写大作业之前不知道
1
2
3
4
5
6
7
8
9
10
11
12
13
using System;
public static class T {
public static bool IsLonger(this string str, int n) {
return str!=null && str.Length> n;
}
}

class B {
public static void Main() {
string s = "abc";
Console.Write(s.IsLonger(2));
}
}

4.0

  • dynamic
    • 可以动态表示任意对象,在编译时不进行语法检查
    • 主要用于 COM 组件的操作

5.0

  • Task
  • await/async
  • PLinq
  • Parallel

6.0

  • 初始化更方便
1
2
3
4
5
6
7
8
class T {
public string Name {
get;
} = "Mr.";
public intAge => 20;
public intAdd(inta, intb) => a+b;
public void Fun( string s ) => Console.Write(s);
}