0%
[TOC]
深入理解 C# 语言
1. 类型与转换
存储位置 |
栈 |
堆 |
默认值 |
Zeored |
null |
等号操作 |
所有值复制 |
指向同一个对象 |
- 值类型的转换
- 数字类型之间可以互相转化
- 隐式转换
- 显式转换(强制类型转换)
- 整型提升
- 枚举类型与数字类型之间可以显式转换(强制类型转换)
- 结构类型之间不能转换
- 引用类型转换
as
- 引用类型与值类型的转换
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. 多态与虚方法调用
多态定义
- 在面向对象的系统中,多态性是一个非常重要的概念,它允许客户对一个对象进行操作,由对象来完成一系列的动作,具体实现哪个动作、如何实现由系统负责解释
- 在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
或 abstract
或
override
所修饰
- 虚方法不能省略访问控制符
- 不能是 private 的,不能是 static 的
- 因为它们应该可以被子类所覆盖。
- 子类中要覆盖父类的虚方法,必须用 override
- 否则认为是新(new)的一个方法,并隐藏了父类的方法,不会实行虚方法调用
- 覆盖和被覆盖的方法必须有相同的可访问性和相同的返回类型
- 重要例子
虚方法与非虚方法
- 虚方法调用的方法是由对象实例的类型所决定
- 非虚方法调用的方法是由所声明的对象变量来决定的
最可派生的方法
- 继承链中既有 override 也有 new
- 示例
4. 动态类型确定
is 运算符
== 和 !=
- 值类型相等
- 引用类型的相等
- 是判断是否是同一对象
- 除非重载了 == 及 != 操作
- 对于 string 等类型,已经进行了重载
- 对于两个 boxing 的对象,== 总是 false
得到类型信息
- typeof 运算符
对象.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" ), }; } }
|
反射
5. 对象构造与析构
构造方法
- 构造方法的初始化部分,使用
this
及 base
- 调用本类或父类的构造方法
- 不用
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(); B():base(x) {} public static void Main(){} }
|
构造顺序
- 执行过程(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); } }
|
析构方法
~类名(){}
- 编译器生成的构造方法名字为
ctor()
- 生成的析构方法名字为
Finalize()
- 不能显式地调用析构方法
自动垃圾回收
- 垃圾回收(garbage collection)
- 自动回收
- 强制回收
显式资源管理
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>
- 匿名方法
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); }
|