本文归纳整理C#的一些知识点,便于快速浏览与掌握C#语言的一些基本概念。
本文并没有很好地层次与组织,抄了不少,写了不少,想到什么,就写什么。
01 类 class
类是C#等面向对象编程语言(Object-oriented programming language,OOP)的基本元素。
类是软件发展史上最重要的发明,大大提高了软件开发效率与可靠性,正是因为有了类才有了软件的爆发式增长。
类是一种用户定义的引用数据类型,也称“类类型”。每个类包含数据说明和一组操作数据或传递消息的函数。类的实例称为对象。类是对现实生活中一类具有共同特征的事物的抽象。如果一个程序里提供的数据类型与应用中的概念有直接的对应,这个程序就会更容易理解,也更容易修改。一组经过很好选择的用户定义的类会使程序更简洁。此外,它还能使各种形式的代码分析更容易进行。特别地,它还会使编译器有可能检查对象的非法使用。
类的内部封装了属性和方法,用于操作自身的成员。类是对某种对象的定义,具有行为(behavior),它描述一个对象能够做什么以及做的方法(method),它们是可以对这个对象进行操作的程序和过程。它包含有关对象行为方式的信息,包括它的名称、属性、方法和事件。类的构成包括成员属性和成员方法(数据成员和成员函数)。数据成员对应类的属性,类的数据成员也是一种数据类型,并不需要分配内存。成员函数则用于操作类的各项属性,是一个类具有的特有的操作,例如“学生”可以“上课”,而“水果”则不能。类和外界发生交互的操作称为接口interface或代理delegate。
类的三个特性
(1)封装性 将数据和操作封装为一个有机的整体,由于类中私有成员都是隐藏的,只向外部提供有限的接口,所以能够保证内部的高内聚性和与外部的低耦合性。用者不必了解具体的实现细节,而只是要通过外部接口,以特定的访问权限来使用类的成员,能够增强安全性和简化编程。
(2)继承性 更符合认知规律,使程序更易于理解,同时节省不必要的重复代码。
(3)多态性 是指同一操作作用于不同对象,可以有不同的解释,产生不同的执行结果。在运行时,可以通过指向父类(基类)的指针,来调用实现子类(派生类)中的方法。
类可理解为一座建筑物内的一间房子,或者是一个零件。
与类class等同的有结构体struct、枚举enum、接口interface与代理delegate。
类的成员包括属性attribute、方法method(或称为函数function)。
类定义内可包括类class、结构体struct、枚举enum、接口interface与代理delegate(是的!我没写错,你没看错!类的定义内还可以再定义这些!!!)。
你可以理解类中的类,是房间里面的帐篷。
public class PragmaNode
{
/// <summary>
/// 定位令牌
/// </summary>
public Token Token { get; set; } = null;
/// <summary>
/// 提取有效的 Pragma 标志
/// </summary>
/// <param name="pragma"></param>
/// <returns></returns>
private void Pragma_Segments(out List<Token> segments, out List<string> pragma)
{
// ...
}
}
02 命名空间 namespace
命名空间是一些类的集合。
命名空间可以理解为一座建筑物,或者是一个由很多零件组成的部件。
需要使用不是自己定义的类时,需要用 using 导入相应的命名空间。
using System;
using System.IO;
using System.Text;
using System.Collections;
using System.Collections.Generic;
using Newtonsoft.Json;
Visual Studio 菜单【项目】【管理NuGet程序包(N)...】可以非常容易获得大量可用的基础部件。
03 权限 permission
权限是所有管理软件的核心,也是编程语言的核心。
从软件的商业化角度而言,没有比权限管理更加只要的非算法因素了。
不能理解与熟练应用权限,你的编程水平还徘徊于门外。
计算机语言中的“权限”指的是成员(指类、类属性与类方法、变量)的可访问性约定。
C#语言通过两种方式对成员的权限加以规定:(1)访问修饰符。(2)大括号。
03.01 访问修饰符
(1)public,公开,类及类成员的修饰符,对访问成员没有级别限制;
(2)private,私有,类成员的修饰符,只能在类的内部访问;
(3)protected,受保护的,类成员的修饰符,在类的内部或者在派生类中访问,不管该类和派生类是不是在同一程序集中;
(4)internal,内部的,类和类成员的修饰符,只能在同一程序集(Assembly)中访问;
(5)protected internal,受保护的内部:如果是继承关系,不管是不是在同一程序集中都可以访问;如果不是继承关系只能在同一程序集中访问。
03.02 大括号
一对大括号,限制了局部变量的可访问范围。
大括号就是房子里面收拾东西的收纳盒。适量的收纳盒,使得房间整洁合理。
很多软件的BUG出现于局部变量与全局变量的冲突,使用大括号进行可以极大地较少此类错误的发生。
在C#中,括号“{”和“}”是一种范围标志,是组织代码的一种方式,用于标识应用程序中逻辑上有紧密联系的一段代码的开始与结束。
大括号可以嵌套,以表示应用程序中的不同层次。
switch(a)
{
case 1:
{
int b = a * 10;
break;
}
case 2:
{
int b = a / 10;
break;
}
}
或:
// 顶层逻辑
{
// 二层逻辑
{
}
}
也就是说,{ } 不一定非在 for 等程序块中使用。一对大括号就是很好的程序逻辑的体现。
python、FORTRAN 77等语言因为没有大括号,使得程序的可维护性极差。如果将python用于大规模软件的开发,其后续维护与支持都是代价高昂甚至是无底洞。
04 保留字(关键字,reserved words)
在C#代码中的保留字,是对C#有特定意义的字符串。
所有计算机语言都有保留字。
下面这些词是C#的主要保留字。
abstract,as,base,bool,break,byte,case,catch,char,checked,
class,const,continue,decimal,default,delegate,do,double,else,
enum,event,explicit,extern,false,finally,fixed,
float,for,foreach,get,goto,if,implicit,int,
interface,internal,lock,long,namespace,new,
null,object,operator,out,override,partial,params,private,
protected,public,readonly,ref,return,sbyte,
sealed,set,short,sizeof,static,string,
struct,switch,T,this,throw,true,try,typeof,uint,
ulong,unchecked,unsafe,ushort,using,var,value,virtual,
void,volatile,while,yield,
from,in,group,orderby,where,select,let,into,join,equals,
dynamic,async,await,nameof,when,_,is,
stackalloc,global,nint,unint,and,with,init,not,or,record,
using,for,foreach,if,while,catch,switch,lock,fixed,
else,do,try,finally,unsafe,checked,unchecked,case,default,
double,System.Double,Double,
float,System.Single,Single,
decimal,System.Decimal,Decimal,
sbyte,System.SByte,SByte,
byte,System.Byte,Byte,
short,System.Int16,Int16,
ushort,System.UInt16,UInt16,
int,System.Int32,Int32,
uint,System.UInt32,UInt32,
long,System.Int64,Int64,
ulong,System.UInt64,UInt64,
nint,System.IntPtr,IntPtr,
unint,System.UIntPtr,UIntPtr,
bool,System.Boolean,Boolean,
string,System.String,String,
char,System.Char,Char,
object,System.Object,Object,
var,void,dynamic,
,async,await,as,event,explicit,implicit,
is,new,out,override,params,
ref,return,volatile,
保留字是不能用于自定义属性、变量及方法(函数,运算符重载除外)的。
因而应该避免使用保留字。
当然,你无需记忆这些保留字。如果用错了,Visual Studio 会自动提示!!!
05 语句 sentence
程序中执行一个运算的句子,可称为语句,用分号“;”结束。
例如:
a = b + c;
在一行中可以书写多条语句,也可以将一条语句书写在多行上。
06 程序段(块)
类class的函数(方法)是有一系列的程序段(段落)组成的,程序段内包含有若干语句。
按执行方式的区别,有很多种程序段。例如条件程序段:
if(...) { ... } else { ... }
其他的包括:
for(...) { ... continue; }
foreach(... in ...) { ... continue; }
do { ... } while(...);
while(...) { }
switch(...) { case ...: break; default: ... }
using(...) { ... }
fixed(...) { ... }
lock(...) { ... }
unsafe { ... }
checked { ... }
unchecked { ... }
try { ... } catch(...) { ... } finally { ... }
07 缩进与空格
缩进用于表示代码的结构层次,但是缩进可以清晰地表示程序的结构层次,在程序设计中应该使用统一的缩进格式书写代码。
空格有两种作用,一种是语法要求,必须遵守,一种是为使语句不至于太拥挤。
例如:
int a = 4;
幸运的是:Visual Studion 具有自动排版功能。
只需要删除最后一个 大括号,再重新输入大括号即可自动排版。
08 字母大小写
大写“X”与小写“x”对C#来说,是两个不同的字符。
int X = 10;
int x = X + 10;
09 注释
C#语言支持多种注释。
(1)单行注释以双斜线“// ”开始,不能换行。
// 单行注释
(2)多行注释以“/*”开始,以“*/”结束,可以换行。
/*
多行注释
*/
(3)/// 注释,专门用于类属性、方法的注释。这种注释具有极大的好处与应用。在属性或方法引用的地方,鼠标可显示注释内容,了解属性、方法的说明与使用方法等。
/// <summary>
/// PRAGMA类型
/// </summary>
public PragmaType Type { get; set; } = PragmaType.UNDEFINED;
/// <summary>
/// 提取有效的 Pragma 标志
/// 同时返回 #define 预定义信息
/// </summary>
/// <param name="pragma"></param>
/// <returns></returns>
private void Pragma_Segments(out List<Token> segments, out List<string> pragma)
{
}
(4)#region 与 #endregion 可带说明的块注释。
#region 多谱系图像合成算法
...
#endregion
(5)#if __UNUSED__ 这样的预处理,也可以视为一种注释。
#if DEBUG
// 内测版本代码
#else
// 发行版本代码
#endif
10 基本数值类型
10.01 整数
有符号整数包括sbyte(符号字节型)、short(短整型)、int(整型)、long(长整型)。
无符号整数包括byte(字节型)、ushort(无符号短整型)、uint(无符号整型)、ulong(无符号长整型)。
10.02 浮点数(实数)
浮点数类型包括float(单精度)、double(双精度)、decimal(金融行业,十进制型)。
布尔类型也属于数值,后面再叙。
11 字符与字符串
11.01 Unicode字符集
C#支持Unicode字符集。
建议你的代码与数据全面支持Unicode,尤其是UTF-8字符集。
11.02 char(字符型)
char(字符型):数据范围是0~65535之间的Unicode字符集中的单个字符,占用2个字节。
char(字符型)表示无符号16位整数,char(字符型)的可能值集与Unicode字符集相对应。
11.03 string(字符串型)
C# 中 String 与 string 相同。
string(字符串型):指任意长度的Unicode字符序列,占用字节根据字符多少而定。
string(字符串型)表示包括数字与空格在内的若干个字符序列,允许只包含一个字符的字符串,甚至可以是不包含字符的空字符串。
12 布尔类型和对象类型
12.01 bool(布尔型)
C# 中 bool 与 boolean 相同。bool 看起来更简洁。
bool表示布尔逻辑量。bool(布尔型)数据范围是“true”(真)和“false”(假)。
bool(布尔型)名义上占用一个字节,事实并不如此。
bool(布尔型)和布尔值 true (真)、 false 都是保留字。
12.02 object(对象型)
object可以表示任何类型的值,其占用字节视具体表示的数据类型而定。
object(对象型)是所有其他类型的最终基类。
C#中的每种类型都是直接或间接从object类型派生的。
12.03 var 推断类型(其实也就是弱化类型的定义)
var可代替任何类型,编译器会根据上下文来判断你到底是想用什么类型,类似 object,但是效率比object高点。
我们的建议是,非不得已不用 var 与 object 。
13 再论 var
var 可能是从java系列语言获得的IP。
使用var定义变量时有以下四个特点:
(1) 必须在定义时初始化。也就是必须是:
var s = "abcd";
形式,而不能是如下形式:
var a;
a = "abcd";
(2)一但初始化完成,就不能再给变量赋与初始化值类型不同的值了。
(3)var要求是局部变量。
(4)使用var定义变量和object不同,它在效率上和使用强类型方式定义变量完全一样。
优点:
简单。
缺点:
利己不利他。大大增加了别人(或者是未来的自己)阅读代码、维护代码的难度。
喜欢使用 var 的程序员在团队中不受欢迎!
建议:
最好不用!最好不用!最好不用!
14 变量
变量是某种数值、数据类型的一个或一组实例。
14.01 变量声明(定义)
变量声明的格式为:
(1)数据类型名称 变量名列表;
(2)数据类型名称 变量名列表 = 初值;
例如:
// 声明一个整型变量
int a;
// 声明一个整型变量,带初值
int b = 2;
// 声明一个布尔型变量
bool c;
// 声明一个十进制变量
decimal d;
14.02 多个变量
虽然可以一次声明多个变量,例如:
// 声明两个有符号字节型变量
sbyte a, b;
一次声明多个变量,变量名之间用逗号分隔。
但不鼓励这样做!这会大大降低程序的可读性、可维护性、拓展性。
建议使用逐个定义,并给出初值。
sbyte a = 0;
sbyte b = 1;
14.03 变量赋值
C#规定,变量必须赋值后才能引用。为变量赋值需使用赋值号“=”。例如:
// 为变量赋值32
int a;
a = 32;
也可以使用变量为变量赋值,例如:
bool b;
// 为变量赋值true(假设open为已声明的bool型变量,其值为true)
b = open;
15 常数
15.01 整型常数
整型常数即整数,整型常数有三种形式:
(1)十进制形式,即通常意义上的整数,如:123,48910等。
(2)十六进制形式,输入十六进制整型常数,需要在数字前面加“0x”或“0X”,如:0x123,0X48910等
(3)八进制形式,输入八进制整型常数,需要在数字前面加“0”,如:0123,038等。
(4)二进制形式,如:0b010101010。
15.02 浮点数(实型)常数
实型常数即带小数的数值,实型常数有两种表示形式:
(1)小数形式,即人们通常的书写形式,如:0.123,12.3,.123等等。
(2)指数形式,也叫科学记数,由底数加大写的E或小写的e加指数组成。
如:123e5或123E5都表示123×10^5。
15.03 字符常数
字符常数表示单个的Unicode字符集中的一个字符,通常包括数字、各种字母、标点、符号和汉字等。
字符常数用一对英文单引号界定,如,'X','x','+','国' 等等。
特殊字符的处理
在C#中,有些字符不能直接放在单引号中作为字符常数,这时需要使用转义符来表示这些字符常数,转义符由反斜杠“\”加字符组成,如 '\n' 。
15.04 字符串常数
字符串常数是由一对双引号界定的字符序列,例如:
"欢迎使用C#!"
"I am a student."
需要注意的是,即使由双引号界定的一个字符,也是字符串常数,不能当做字符常数看待,例如,'A'与"A",前者是字符常数,后者是字符串常数。
16 const 与 readonly 常量
容易混淆的两种常量(不是常数!)
静态常量 const 是指编译器在编译时候会对常量进行解析,并将常量的值替换成初始化的那个值。
动态常量 readonly 的值则是在运行的那一刻才获得的。编译器编译期间将其标示为只读常量,而不用常量的值代替,这样动态常量不必在声明的时候就初始化,而可以延迟到构造函数中初始化。
17 类型转换
17.01 隐式转换
隐式转换是系统自动执行的数据类型转换。隐式转换的基本原则是允许数值范围小的类型向数值范围大的类型转换,允许无符号整数类型向有符号整数类型转换。
17.02 显式转换
显式转换也叫强制转换,是在代码中明确指示将某一类型的数据转换为另一种类型。显式转换的一般格式为:
(数据类型名称)数据
例如:
int x = 600;
short z = (short)x;
显式转换中可能导致数据的丢失,例如:
decimal d = 234.55M;
int x = (int)d;
17.03 类型转换方法
(1) Parse方法
Parse方法可以将特定格式的字符串转换为数值。Parse方法的使用格式为:
数值类型名称.Parse(字符串型表达式)
例如:
int x = int.Parse("123");
(2) ToString方法
ToString方法可将其他数据类型的变量值转换为字符串类型。ToString方法的使用格式为:
变量名称.ToString( )
例如:
int x = 123;
string s = x.ToString();
string t = x + "";
18 运算符与表达式
① 一元运算符:-(取负)、+(取正)、++(增量)、--(减量)。
② 二元运算符:+(加)、-(减)、*(乘)、/(除)、%(求余)。
18.01 字符串运算符与字符串表达式
字符串运算符只有一个,即“+”运算符,表示将两个字符串连接起来。例如:
string connected = "abcd" + "ef";
// connec的值为“abcdef”
“+”运算符还可以将字符型数据与字符串型数据或多个字符型数据连接在一起,例如:
string connec="abcd" + 'e' + 'f';
// connec的值为“abcdef”
18.02 关系运算符与关系表达式
依次为大于,小于,大于等于,小于等于,等于,不等于。
用于字符串的关系运算符只有相等“==”与不等“!=”运算符。
>,<,>=,<=,==,!=。
18.03 逻辑运算符与逻辑表达式
在C#中,最常用的逻辑运算符是!(非)、&&与、||(或)。
例如:
// b1的值为false
bool b1 = !true;
// b2的值为false
bool b2 = (5>3) && (1>2);
// b3的值为true
bool b3 = (5>3) || (1>2);
18.04 条件运算符与条件表达式
条件运算符是C#中唯一的三元运算符,条件运算符由符号“?”与“:”组成,通过操作三个操作数完成运算,其一般格式为:
布尔类型表达式?表达式1:表达式2
例如:
int a = (b>10) ? 0 : 1;
18.05 赋值运算符与赋值表达式
在赋值表达式中,赋值运算符左边的操作数叫左操作数,赋值运算符右边的操作数叫右操作数。左操作数通常是一个变量。
复合赋值运算符,如“*=”、“/=”、“%=”、“+=”、“-=”等。
例如:
a /= 10;
19 静态成员和非静态成员的区别
静态变量使用 static 修饰符进行声明,在类被实例化时创建,通过类进行访问。
不带有 static 修饰符声明的变量称做非静态变量,在对象被实例化时创建,通过对象进行访问;
定义:
public class KPoint
{
public static int DIM = 3;
public int[] XYZ = new int[3];
}
使用:
KPoint kx = new KPoint();
for(int i=0; i<KPoint.DIM; i++)
{
k[i] = 0;
}
一个类的所有实例的同一静态变量都是同一个值,同一个类的不同实例的同一非静态变量可以是不同的值;
静态函数的实现里不能使用非静态成员,如非静态变量、非静态函数等。
20 extern 外援
extern 修饰符用于声明由程序集外部实现的成员函数。
经常用于系统API函数的调用(通过 DllImport )。注意,和DllImport一起使用时要加上 static 修饰符。extern也可以用于对于同一程序集不同版本组件的调用(用 extern 声明别名)。不能与 abstract 修饰符同时使用。
21 abstract 抽!像!
abstract 修饰符可以用于类、方法、属性、事件和索引指示器(indexer),表示其为抽象成员。abstract 不可以和 static 、virtual 一起使用。声明为 abstract 成员可以不包括实现代码,但只要类中还有未实现的抽象成员(即抽象类),那么它的对象就不能被实例化,通常用于强制继承类必须实现某一成员。
22 internal 特供
internal 修饰符可以用于类型或成员,使用该修饰符声明的类型或成员只能在同一程集内访问接口的成员,不能使用 internal 修饰符。值得注意的是,如果为 internal 成员加上了 protected 修饰符,这时的访问级别为internal 或 protected。只是看字面意思容易弄错,许多人认为 internal protected应该是“只有同一个程序集中的子类可以访问”,但其实它表示“同一个程序集中的所有类,以及所有程序集中的子类都可以访问”。
23 sealed 胶带密封
sealed 修饰符表示密封用于类时,表示该类不能再被继承,不能和 abstract 同时使用,因为这两个修饰符在含义上互相排斥,用于方法和属性时,表示该方法或属性不能再被继承,必须和 override 关键字一起使用,因为使用 sealed 修饰符的方法或属性肯定是基类中相应的虚成员,通常用于实现第三方类库时不想被客户端继承,或用于没有必要再继承的类以防止滥用继承造成层次结构体系混乱恰当的利用 sealed 修饰符也可以提高一定的运行效率,因为不用考虑继承类会重写该成员。
24 override 和 overload
override(重写,覆盖) (1)方法名、参数、返回值相同。 (2)子类方法不能缩小父类方法的访问权限。 (3)子类方法不能抛出比父类方法更多的异常(但子类方法可以不抛出异常)。 (4)存在于父类和子类之间。 (5)方法被定义为final不能被重写。 (6)被覆盖的方法不能为private,否则在其子类中只是新定义了一个方法,并没有对其进行覆盖。
overload(重载,过载) (1)参数类型、个数、顺序至少有一个不相同。 (2)不能重载只有返回值不同的方法名。 (3)针对于一个类而言。 (4)不能通过访问权限、返回类型、抛出的异常进行重载; (5)方法的异常类型和数目不会对重载造成影响;
25 索引器 indexer
实现索引指示器(indexer)的类可以象数组那样使用其实例后的对象,但与数组不同的是索引指示器的参数类型不仅限于int简单来说,其本质就是一个含参数属性。
public class Team
{
private string[] Members = new string[] { "Messi", "CR7", "MP" };
public string this[int idx]
{
get
{
if (idx >= 0 && idx < Members.Length)
return Members[idx];
else
return string.Empty;
}
set
{
if (idx >= 0 && idx < Members.Length)
Members[idx]= value;
}
}
使用:
Team tx = new Team;
string m = tx[0];
26 new 修饰符与 new 操作符
new 修饰符与 new 操作符是两个概念。new 修饰符用于声明类或类的成员,表示隐藏了基类中同名的成员。而new 操作符用于实例化一个类型new 修饰符只能用于继承类,一般用于弥补基类设计的不足。new 修饰符和 override 修饰符不可同时用在一个成员上,因为这两个修饰符在含义上互相排斥
27 this 自闭
this 是一个保留字,仅限于构造函数和方法成员中使用在类的构造函数中出现表示对正在构造的对象本身的引用,在类的方法中出现表示对调用该方法的对象的引用,在结构的构造上函数中出现表示对正在构造的结构的引用,在结构的方法中出现表示对调用该方法的结果的引用this 保留字不能用于静态成员的实现里,因为这时对象或结构并未实例化在 C# 系统中,this 实际上是一个常量,所以不能使用 this++ 这样的运算this 保留字一般用于限定同名的隐藏成员、将对象本身做为参数、声明索引访问器、判断传入参数的对象是否为本身
28 属性访问 get & set
属性访问器(Property Accessor),包括 get 访问器和 set 访问器分别用于字段的读写操作其设计目的主要是为了实现面向对象(OO)中的封装思想。根据该思想,字段最好设为private,一个精巧的类最好不要直接把字段设为公有提供给客户调用端直接访问另外要注意属性本身并不一定和字段相联系
29 接口 interface
接口可以包含属性、方法、索引指示器和事件,但不能包含常量、域、操作符、构造函数和析构函数,而且也不能包含任何静态成员。
30 抽象类abstract和接口interface
抽象类(abstract class)可以包含功能定义和实现,接口(interface)只能包含功能定义抽象类是从一系列相关对象中抽象出来的概念, 因此反映的是事物的内部共性;接口是为了满足外部调用而定义的一个功能约定, 因此反映的是事物的外部特性分析对象,提炼内部共性形成抽象类,用以表示对象本质,即“是什么”为外部提供调用或功能需要扩充时优先使用接口
31 释放内存
C#在内存管理方面提供了GC(Garbage Collection),负责自动释放托管资源和内存回收的工作。但在以下两种情况需要我们手工进行资源释放:一、由于它无法对非托管资源进行释放,所以我们必须自己提供方法来释放对象内分配的非托管资源,例如你在对象的实现代码中使用了一个COM对象;二、你的类在运行是会产生大量实例(象GIS 中的Geometry),必须自己手工释放这些资源以提高程序的运行效率最理想的办法是通过实现一个接口显式的提供给客户调用端手工释放对象,System 命名空间内有一个 IDisposable 接口,拿来做这事非常合适,省得我们自己再声明一个接口了。
32 StringBuilder 夹子
String 在进行运算时(如赋值、拼接等)会产生一个新的实例,而 StringBuilder 则不会。所以在大量字符串拼接或频繁对某一字符串进行操作时最好使用 StringBuilder,不要使用 String
另外,对于 String 我们不得不多说几句:
(1) 它是引用类型,在堆上分配内存
(2) 运算时会产生一个新的实例
(3) String 对象一旦生成不可改变(Immutable)
33 explicit 和 implicit
explicit 和 implicit 属于转换运算符,如用这两者可以让我们自定义的类型支持相互交换explicti 表示显式转换,如从 A -> B 必须进行强制类型转换(B = (B)A)implicit 表示隐式转换,如从 B -> A 只需直接赋值(A = B)隐式转换可以让我们的代码看上去更漂亮、更简洁易懂,所以最好多使用 implicit 运算符。不过!如果对象本身在转换时会损失一些信息(如精度),那么我们只能使用explicit 运算符,以便在编译期就能警告客户调用端。
34 params 核酸排队,永远的记忆
params 关键字在方法成员的参数列表中使用,为该方法提供了参数个数可变的能力它在只能出现一次并且不能在其后再有参数定义,之前可以。
35 Reflection 是反射不是发射
反射,Reflection,通过它我们可以在运行时获得各种信息,如程序集、模块、类型、字段、属性、方法和事件通过对类型动态实例化后,还可以对其执行操作简单来说就是用string可以在runtime为所欲为的东西,实际上就是一个.net framework内建的万能工厂一般用于插件式框架程序和设计模式的实现,当然反射是一种手段可以充分发挥其能量来完成你想做的任何事情(前面好象见过一位高人用反射调用一个官方类库中未说明的函数。。。)
未完不续。