晴朗笔记

努力做好自已,其他交给时间

C#基础知识总结

1、使用命名空间的语法using SpaceName;
2、C#可执行文件的入口点Main方法(M必须大写)
3、C#要求变量必须先被初始化然后才能被操作使用:
a、类、结构中的字段没有显示初始化则默认为0;
b、局部变量必须显示初始化;
c、引用类型必须初始化指向被引用对象;
否则编译出错
4、C#不允许隐藏变量,即,子作用域中不允许出现上层作用域同名的变量。
5、C#中只能把局部变量和字段声明为常量,没有其他常量了。
6、const常量声明时初始化,不可修改;编译时必须能确定其值,如果要总变量中提取值来初始化常量,可用只读字段;常量总是静态的,不需要也不允许常量+static修饰符
7、值类型和引用类型:值类型存储在堆栈上,而引用类型则是对存储在托管堆中的对象的引用。
8、C#中的空引用是null(小写)
9、需要自定义值类型,则定义结构
10、基本预定义类型:
===========
值类型如下:
整型:sbyte、byte 8位
ushort、short 16
ulong、long 64
uint、int 32
指定数字类型可在数字后面+u、U、l、L,注意l和1混淆。
浮点:指定为float可在数字后面+f、F
非基本类型:decimal:128位,性能损失 指定数字为decimal可在数字后面+M、m
bool:不能与整型值互换,不能0表示false,非0表示true。
char:16位 没有uchar类型

===========
引用类型如下:

object:根类型
string:字符串类型。赋值后string引用同一对象,但修改一个引用时会生成新的对象。
字符串前+@,则对字符串内容不做转义处理

11、C#中if后的条件语句必须是bool值。
12、switch的case后必须是常量表达式,可以是字符串。要么case后是空的,要么case后面必须有break。case后常量不能相同。
13、foreach对集合中各项进行只读操作。

14、goto:不能goto进入for循环中;不能跳出类的范围;不能退出try...catch后面的finally块。

15、int[] integers = new int[32]; C#中数组是引用类型,要用new生成实例,所以是动态的。
16、namespace X.X.X{}允许
17、using System;如果命名空间中类重名,则必须全名使用该类。
18、using ok = System; ok:bject XXX = ....命名空间别名定义与使用。命名空间可以被返回,object.GetType().NameSpace;
19、如果存在多个Main方法,可以使用编译选项/main classname,指定入口Main函数。
20、string[] args是Main的参数。
21、C#编译成/t:exe /t:library /t:module /t:winexe。使用dll的方法:/r编译选项。
22、控制台输入输出:Console.ReadLine(); Console.WriteLine("{0, 5} is sb!\n", szOK);
{索引, 宽度:格式精度}
23、预编译命令
#define
#undef
#if
#elif
#else
#endif

允许嵌套,允许条件编译的条件为bool表达式(支持! == != || && 符号存在则为true,反之为false)。

#warning "warningWords" 给出警告信息,继续编译
#error "errorWords" 给出错误信息,停止编译

#region 给编辑器用,无语言、语义上的含义。
#endregion

#line 164 "Core.cs" 改变编译器在警告和错误信息中显示的文件名和行号信息。
#line default 恢复。

#pragma warning disable 169//抑制指定编译警告
...
pragma warning restore 169//恢复指定编译警告

24、保留字前+@可以作为标志符,例如if不是标志符,@if是标志符。标志符可以是Unicode字符,\uXXXX(16进制代码)语法即可。

25、C#代码风格约定:
a、变量命名不使用任何前缀
b、命名空间、类、方法、变量、公共|受保护的成员字段:Pascal大小写命名形式,所有单词首字母大写,其他小写。
c、私有成员字段、形参:camel大小写形式。私有成员字段,下划线开始。
d、仅大小写不同的变量会与语言的互操作性冲突。

26、结构体:值类型,堆栈上,不可被继承;类:引用类型,堆上,可被继承;字段默认值都是0
27、数据成员:字段、常量、事件。
28、函数成员:(静态)方法,属性,构造函数(类同名,无返回值),终结器(相比C++的析构很少使用,CLR自动进行垃圾收集,执行时间不可预期),运算符,索引器(以数组或者集合的方式进行索引)。
29、C#中没有全局函数,所有方法必须与类挂钩,但可以是静态方法(与类挂钩,但不与实例挂钩)。
30、C#中不能将实现代码与方法接口分离。
31、方法定义:[modifiers] return_type MethodName([parameters]){...}
注意:
a、方法的访问设置必须单独设置,即一个方法对应一个public或private。
b、返回值不可缺省,没有则是void。
32、C#静态方法调用:classname.staticmethod(),C++中:classname::staticmethod()
33、C#中string作为参数传递和值传递一样的表现。string对象是不能改变的,改变则创建新的字符串。
34、ref强制引用传递参数。相当于C++中的&。方法定义时,参数声明前+ref,调用时也需要+ref。
35、传递入函数的参数必须进行初始化。
36、使用out关键字表示用来接收返回值的参数,此时,该参数不需要初始化。声明与调用时都需要+out。
37、C#方法重载,不支持默认参数,不支持可选参数,此外,重载方法不能只有返回类型的区别,不能仅根据参数是ref还是out区分。
38、属性:客户机代码角度观察,是一个字段,但读写该字段时会触发指定操作。
语法:
public string SomeProperty
{
get//必须无参数
{
return "this is the property value"//返回属性声明相同的类型
}
set//无显式参数,但编译器假定有一个与属性同类型的参数value,值就是客户机代码赋入值。
{
//do whatever needs to be done to set the property
}
}
39、只读属性、只写属性。只有get,只有set。后者不是好的编程方式,可以用方法代替。
40、get、set访问级别可以不同。注意,get、set必须至少一个是public,否则编译错误。因为,此时语义上,可以是private 字段,而不需要是属性(供客户机代码使用)。

41、C#实例化时会对未初始化的数据成员自动初始化为默认值。
42、静态构造函数,用以初始化类的静态字段或属性,仅在第一次使用类之前执行一次。
a、没有访问修饰符
b、没有参数
c、只能访问静态成员,不能访问实例成员
d、只运行一次
43、构造函数中调用构造函数(同级构造函数):构造函数初始化器,用以初始化相同字段,可以在各个构造函数中使用。
public Car(string model, uint nWheels)
{
}
public Car(string model) : this(model, 4)
{
}
a、可以调用基类的构造函数,this替换成base即可。
b、仅调用一个构造函数。
44、只读字段:readonly关键字。可以是静态或实例的,仅在构造函数中对只读字段赋值。赋值不需要是常量,可以经过计算得到。
45、结构与类的区别:
a、结构是值类型,类是引用类型,分别存储在堆栈和托管堆中。
b、结构不支持继承。
c、编译器总对结构提供一个无参数的默认构造函数,且不允许替换。
d、结构可以指定字段如何在内存中布局。
46、结构的语法可以使用类的语法,如,使用new在生成对象。但直接以值类型的语法使用也是正确的,即声明后立即使用。
值类型来说,声明变量即意味着分配存储空间。此时的new仅仅调用构造函数而已。
47、结构派生于System.ValueType,System.ValueType派生于System.Object。所有的结构都是如此,且不能被继承。
48、结构不能提供字段的初始值,默认构造函数初始化所有字段为0。
49、partial允许把类、结构或者接口放在多个文件中。编译器自动进行合并。字段,方法,基类或接口都会被合并。
50、静态类:如果类只有静态方法与属性,则该类是静态的。使用static修饰类,编译器会检查该类必须为静态类,且不允许为该类添加实例。
51、实现继承:继承基类函数的实现代码。
接口继承:继承基类函数的签名,但不继承实现代码。
52、C#不允许多重继承,但允许继承自多个接口,即,C#中允许一个类继承自一个基类和任意多个接口。
53、结构可以继承自多个接口。
54、C#中仅有继承,即,公有继承,没有私有继承。
55、C#中如果没有指定基类,则假定System.Object是基类。
56、C#中虚函数与虚属性性质类似,基类中必须标记为virtual(访问修饰符后),同时重载时必须用override标识,重写函数不需要virtual标识。Java中所有函数都是虚拟的。
57、C#中,如果基类和派生类存在相同签名的函数,但是没有用virtual和override标识,那么派生类隐藏基类方法。如果是隐藏方法,必须在派生类中使用new修饰重名方法。
58、派生类中调用基类方法的语法:base.<methodname>()。
59、C#可以使用abstract修饰类与函数,表示抽象类和抽象函数。含有抽象函数的类必须也修饰为abstract,即抽象类。抽象类不能实例化,抽象函数没有执行代码,必须在非抽象的派生类中重写。
60、密封类与密封方法:C#中可以终止继承与重写,sealed修饰类,表示该类不能被继承;修饰函数表示该方法不能被重写。
61、sealed可以保证virtual声明的函数代码的最终形式,其他人不能重写。如果一开始就不希望被重写,就不要声明为virtual函数。

62、C#中类的构造函数既可以调用其他构造函数,也可以调用基类的构造函数。
63、Internal修饰符:只能在包含它的程序集中访问该方法。
64、C#中接口相关:
a、一般接口只能包含方法、属性、索引器、事件的声明。
b、接口不能被实例化,所以接口不允许有构造函数。
c、接口隐藏内部执行方式,所以不允许有字段。
d、接口定义也不允许包含运算符重载,因为包含运算符重载可能会引起一些与其他.net语言不兼容的问题。vb.net不支持运算符重载。
e、接口定义中还不允许声明成员上的修饰符。接口成员总是公共的,不能声明为虚拟或者静态,这由执行的类去完成。
f、接口定义的成员必须被执行的类实现。
65、接口仅仅保证其成员的存在性,类负责确定这些成员是虚拟的还是抽象的。
66、接口引用的强大之处:接口可以引用任何实现该接口的对象,调用该接口成员。如果需要调用该接口以外的方法,则必须强制转换为其他类型,然后再调用。
67、接口的派生等于生成并集。a:b,那么a包含b以及,a中不属于b的部分。
68、C#中只有不安全的代码块中,才允许使用指针。
69、checked和unchecked运算符:
a、被checked标记的代码块执行时会进行溢出检查,发生溢出就抛出异常。
b、如果编译时/checked选项使用,则检查程序中所有未标记代码中的溢出。
c、unchecked标记的代码块,则是禁止溢出检查。
d、unchecked是默认的。使用上来说,unchecked是嵌套在checked代码块中使用的,在需要检查的代码块中,禁止几处代码的溢出检查。
70、is运算符:is是否与特定类型兼容:是该类型,或者派生于该类型。
语法:if (i is object)...
71、as运算符:引用类型的显示类型转换。与类型兼容,则类型转换成功,否则返回false,类似C++的dynamic_cast<>
72、sizeof,与C++中的sizeof同。
注意:
a、只能用于值类型!
b、只能在不安全的代码中使用sizeof运算符。
73、typeof返回一个表示特定类型的System.Type对象。
74、可空类型:
语法:int? a = null;
如果使用可空类型,就必须考虑null值与各种运算符一起使用时的影响。通常,一元、二元操作符中一个操作数为null则结果是null。
可空类型在< <= == != >= >运算符时,只要有一个操作数为null,则结果为false。
75、空接合运算符:
语法:b = a ?? c;
语义:如果a不是null,则b = a,否则b = c
76、C#中两个byte加在一起,返回应当是一个int类型,而不是另一个byte(需要强制转换为byte)。这点跟C++不同。(C#的防溢出处理!)
77、隐式转换;只要能保证值不会发生任何变化,类型转换就可以自动进行。
C#支持的隐式转换的规则基本与C++类似:短的可以转换为长的(包括整型转化为浮点型)。注意:long/ulong转换为float是允许的,会丢失4个字节数据,但此仅表示得到的float值比使用double得到的值精度要低。编译器认为是可以的,所以不会给出警告与错误。无符号的只要数据在有符号范围内,则亦可以进行转换。
78、可空类型-》可空类型 同上(必须显式)
不可空类型-》可空类型 同上(隐式)
可空类型-》不可空类型 不允许隐式类型转换
79、显式转换:只有C风格的类型转换语法,注意,只有!显示转换是否溢出可以用checked关键字检查。
80、C#中类型转换失败可能触发异常,所以要有处理类型转换失败的代码(异常机制)。
可空类型转换为不可空类型时,null为源值,则会触发InvalidOperationException异常。
90、不能在bool类型和其他类型之间任意转换。这点和C++差别相当大~要从字符串中分析得到一个数字或则bool类型,可以用所有类型都有的Parse方法。
91、装箱和拆箱:
作用:值类型----》引用类型 装箱;引用类型----》值类型 拆箱
实质:装箱:运行库为栈上的对象创建一个临时性的引用类型“box”。
注意:
a、只能拆掉装过的箱子!
b、必须确保拆箱得到的值变量有足够的空间存储!否则异常!
代码范例:
long a = 3333
object o = a;//装箱
int j = (int)o;//拆箱

92、对象的相等比较:
a、引用类型的相等比较:System.Object类的方法
ReferenceEquals(),静态方法,相当于C++中的指针比较
虚拟版本的Equals()方法,也是C++中的指针比较,重点在于:可以被重写
静态版本的Equals()方法,实际上内部调用虚拟版本的Equals,但是,该版本有两个参数。如果两个参数都null,则true,一个为null,则false,再不然,调用虚拟版本的进行比较
==运算符一般是比较引用,但是System.String类被微软重载,是比较内容。
93、值类型的相等比较:System.ValueType类的方法
ReferenceEquals(),静态方法,会将值类型装箱,然后再比较引用。注意,对于各个参数会分别装箱,即使参数是同一个,这样使得各个参数绝对不会引用同一个对象,那么值类型调用该函数时,肯定返回false。
Equals()已经被System.ValueType重载,相当于C++的==,真正的值比较。可以继续被重载。
==运算符:默认,结构不提供==运算符(编译错误);可以自行重载该运算符。
94、C#要求所有的运算符重载都声明为public和static,这表示它们与它们的类或结构相关联,而不是与实例相关联,所以运算符重载的代码体不能访问非静态类成员,也不能访问this标识符;这是可以的,因为参数提供了运算符执行任务所需要知道的所有数据。
95、同一运算符亦可以重载成多种形式。注意运算符重载的形式:public static ClassName operator+(...){...}
96、比较运算符的重载。
C#中要求比较运算符必须成对重载,其中==和!= >和< >=和<=各自配对。
97、如果重载==和!=,同时应当重载Equals()和GetHashCode()方法,否则会给出编译警告。Equals()应当和==结果保持一致。
98、不要通过Equals()的静态版本来重载运算符。如果出现==左侧为null,则会出现null.Equals的调用,会异常。
99、赋值运算符不能被显示重载,会自动隐式重载。
100、自定义类型的类型转换:定义为类的一个成员运算符,数据类型必须标记为隐式或者显式。
注意语法与运算符重载的区别:
public static implicit operator float(...){...}
101、定义为隐式类型转换的运算符,既可以隐式转换,也可以显示转换。
102、uint到float是隐式转换。会有精度损失,但是微软认为这种错误并不重要。
103、选择作为隐式转换还是显式转换的原则与C#默认原则相同,虽然可以违反,但容易导致错误。
104、圆整错误:
unit dollars = (uint)value;//value是float类型
ushort cent = (ushort)((value - dollars) * 100);
若float = 50.35,cent为多少?答案是34。
value是50.35,但存储为50.34...,value - dollars = 0.34... * 100 = 34.*** 最后得到cent为34
必须用智能圆整操作:System.Convert类中有相关转换方法。
unit dollars = (uint)value;
ushort cent = Convert.ToUInt16((value - dollars) * 100);
注意:System.Convert类有性能损失,只在需要的时候使用。
此外,System.Convert有自己的溢出检查,不需要checked,但是unit dollars = (uint)value;需要。
105、类之间的数据类型转换的两个限制:
a、如果两个类之间存在继承关系,那么就不能在这两个类之间进行数据类型的转换(存在默认的数据类型的转换)。
b、数据类型转换必须在源或者目标数据类型定义的内部定义。一旦一方有了定义,就不能在另一方定义了。只能有一个数据类型转换。
106、基类和派生类之间的数据类型转换。
派生类--》基类,隐式,默认提供
基类--》派生类,自定义(构造函数的形式)
107、装箱和拆箱数据类型的转换:
结构--》引用对象,隐式,装箱过程 复制数据到托管堆中,且对引用对象的操作不会影响结构
引用对象--》结构,显示,拆箱过程 复制数据到结构中,如果类型不对,会抛出异常
108、多重数据类型转换:当进行要求的数据类型转换时,C#编译器没有可用的直接转换方式,C#编译器就会寻找一种方式,把几种转换合并起来。即如果存在a--》b,b--》c的转换,现在要求a--》c(未提供该转换),那么C#编译器可以自动进行此种转换。如果所有转换步骤都是隐式,则合并后的转换也是隐式,否则是显式转换。此种转换可以被用户自定义替换。

109、当存在多条合并路径的时候,C#有其规则做选择。最好的情况是,我们自己设计转换,是所有路径的转换都得到相同的结果。
110、某个方法有多个重载版本。如果传入参数,数据类型不符合任何一个参数版本,那么就会迫使编译器做类型转换。自动转换会进行,但不一定与我们预期的一致。所以最好还是使用显式转换。
111、回调函数:实际上就是方法调用的指针,即,函数指针。这是一个很强大的编程特性。
112、.net以委托的形式实现函数指针的概念。.net中函数指针是有类型特征的,包括其参数和返回值。此种做法好处就在于,类型安全。
113、.net中如果要传递方法,就必须把方法的细节封装在一种新类型的对象中,即委托。委托只是一种特殊的对象类型,其特殊之处在于,其他对象都包含数据,而委托包含的只是方法的细节。
114、在C#中声明委托:
delegate void VoidOperation(uint x);
对比在C++中声明函数指针类型别名:
typedef void (*VoidOperation)(unsigned x);
115、委托与委托的实例,皆称为委托。
116、定义一个委托就是定义一个新类。
117、委托使用示例:
private delegate string GetAString();

GetAString firstStringMethod = new GetAString(x.ToString);

Console.WriteLine("String is" + firstStringMethod());

118、C#在语法上总是带有一个参数的构造函数,这个参数就是委托引用的方法,类型必须匹配定义委托时的签名。
119、静态或者实例方法对于委托来说没有区别,只要匹配签名。
120、匿名方法:委托的另一种形式,用作委托参数的一个代码块。
示例:
delegate string delegateTest(string val);

delegateTest anonDel = delegate(string param)
{
param += mid;
param += " and this was added to the string.";
return param;
};
121、匿名方法的优点:减少系统开销。方法仅在由委托使用的时候才定义。同时会使代码显得比较简单。
122、匿名方法的两条规则:跳转语句不能从匿名方法外部跳到内部,也不能从内部跳到外部。
123、多播委托:包含多个方法的委托,按顺序调用多个方法。
多播委托必须返回void,而编译器看到一个返回void的委托就假定它是多播委托。
用+ += - -=对多播委托进行运算,以增加或去除委托。
注意:其实就是一个入口,按序调用多个同样参数,void返回的函数。
调用方法链的顺序没有正式定义,因此,最好不要编写依赖于特定顺序执行的方法链。
124、事件(事件内容本身不难,但不好表述,可以形式化使用,转载他人文章一篇,以作说明)。
============================================================================
C#委托、事件、自定义事件的理解

125、windows使用的是虚拟寻址系统。该系统把程序可用的内存地址映射到硬件内存的实际地址上,这些任务又windows在后台管理,其实际结果是32位处理器上的每个进程都可以使用4GB的内存--无论机器上有多少硬盘空间。这个4GB内存实际上包含程序的所有部分--包括可执行代码、代码加在的所有DLL以及程序运行时使用的所有变量的内存。这4GB内存成为虚拟地址空间,或虚拟内存,我们为了方便把它们当作一般的内存使用(实际上这也是完全正确的)。
4GB内存中的每个存储单元都是从0开始往上排序的。
在进程的虚拟内存中,有一个区域称为堆栈。堆栈存储不是对象成员的的值数据类型。另外,在调用一个方法时,也使用堆栈复制传递给方法的所有参数。堆栈实际上是向下填充的,自高字节向低字节填充。
如果两个变量同时声明,例如:int a, b;则先后顺序不定的。不过这不会对使用有任何影响。
126、值类型存储在堆栈中。堆栈的优势:性能高;缺点:不够灵活,生命周期限制太死。
127、为了弥补堆栈的缺点,堆出现,用以存储在退出方法后仍然还需要存在的数据。
注意:C#托管堆与C++的堆目的相同,但是不完全相同:C++由程序员完全控制堆内数据,C#则是由GC负责释放不再使用的引用对象。
128、堆上的内存是向上填充的。堆栈中仅存储对堆中对象的引用。在托管堆中的对象只有没有任何变量引用后,才会被删除。
129、GC,垃圾收集器。一般来说,垃圾收集器启动后,会将所有不再使用的对象删除,然后是正在使用和未使用的内存会混合在一起,而不是各自形成一个连续的块。这样导致一个问题,如果分配新的内存,寻找一块合适大小的内存时需要遍历整个堆。C++中堆的使用就是如此,当然C++中一般不使用GC,而是程序员自己控制在适当的时间删除对象。因此,C++中常常会使用内存池来自定义对象的new与delete。C#中则是从更基础的层次试图解决该问题:当垃圾收集启动后,删除不使用的对象后,还会对正在使用中的对象进行压缩,使其移动回到堆的端部,形成一个连续的块。在移动对象的时候,所有引用都需要用正确的新地址来更新,这会由垃圾收集器自动完成。
C#中垃圾收集器的压缩操作是与其他堆的根本区别所在。这样会使平时分配内存的速度大大加快。但是注意:在更新引用,压缩对象时候,是非常消耗资源的,此时,性能会大幅度降低。
130、可以强制调用垃圾收集器(System.GC),但是不常用。此外,垃圾收集器并不保证一次收集过程中能将所有的未引用的对象都从堆中删除。
131、C#堆的特性仅仅针对托管资源,未托管的对象是不能自动释放的。托管类在封装对未托管的资源的直接或者间接引用的时候,需要制定专门的规则,确保未托管的资源在回收类的一个实例时释放。
未托管的资源,主要是与C#中使用指针相关代码联系起来的,指的是垃圾收集器不能访问和管理的资源。
132、为了实现对未托管资源的的自动释放,有两种机制可以选择:
a、使用析构函数。在.net环境中被称为Finalize。
实际上,析构函数会被翻译为如下的IL的对应C#代码:
protect override void Finalize()
{
try
{
//implementation
}
finally
{
base.Finalize()
}
}
目的在于实现C++中的先调用派生类析构函数,在调用基类析构函数的机制。

注意:C#中析构函数的运行时间是不确定的。所以,不能把必须马上要完成的事情放在此处。不能强制调用实例的析构函数。

b、IDisposable接口。
在C#中推荐使用System.IDisposable接口替换析构函数。IDisposable接口定义了一个模式(具有语言及的支持),为释放未托管的资源提供了确定你个的机制,并避免产生析构函数固有的与垃圾收集器相关的问题。
IDisposable接口声明一个方法void Dispose();
Dispose()执行代码显式释放由对象直接使用的哦所有未托管的资源,并在所有实现IDisposable接口的封装对象上调用Dispose()。

优点:完全的对未托管资源的释放控制。
注意:要在实例上调用,也就是不能null.Dispose()。

try
{
theInstance = new ResourceGobbler();
//do your processing
}
finally
{
if (theInstance != null)theInstance.Dispose();
}
C#中使用一个语法来简化对出作用域的继承IDisposable接口类实例的Dispose()调用。
using(theInstance = new ResourceGobbler())
{
//do your processing
}
即使异常,Dispose()也会被调用。

如果对于某些类来说,使用Close()更为恰当,那么在Close中调用Dispose()即可。这样既满足使用Close(),还可以使用using。

133、最安全的方法是,同时使用IDisposable接口和析构函数。用一个变量标识是否调用过资源释放,在Dispose()和析构中根据标识选择是否调用资源释放。
134、一般,Dispose()意味着要清除所有资源,包括托管的与未托管的。而析构则仅负责未托管的,其他由垃圾收集器负责。
135、.net平台下,除开C++.net外,类都是默认托管的。也就是,如果不涉及到非托管资源,那么类不使用两种机制也是托管的,new出来用就可以了。
136、C#中使用引用的原因:使C#语言易于使用,降低用户内存管理所需要考虑的难度。
137、C#中使用指针的两个原因:
a、向后兼容性。windows api函数可能是以指针作为参数的,这样我们可以继续使用。
b、性能。指针使我们可以自己控制对数据的访问与修改,这样我们可以自行优化性能。
缺点:使用指针容易出错。
138、强烈推荐,C#中不要轻易使用指针:难以编写和调试,而且无法通过CLR的内存类型安全检查。
139、C#只允许在标记为不安全的代码中使用指针。标记不安全代码的关键字unsafe。
140、unsafe可以用来标记类成员(包括函数、字段等)、代码块;不能用来标记局部变量。不安全的局部变量,必须在不安全的方法或者语句块中声明和使用。
141、编译带有不安全代码的代码,必须告诉C#编译器。编译命令为:
csc /unsafe MySource.cs
csc -unsafe MySource.cs
142、int *pX, pY;
C++中表示一个指针,一个整型;C#中表示两个指针。
C#中*是与int一起构成一个类型的,即,C#中*是类型相关的,而不像C++是变量相关的。
142、&取地址运算符。*间接寻址运算符。
143、跨越DWORD边界存储数据通常会降低硬件的性能。因此,.net运行库通常会给某些数据类型加上一些空间,使它们占用的内存是4的倍数。例如,short占用2个字节,但是放在堆栈中,仍然会是堆栈指针减少4,而不是2。
144、可以把指针声明指向任意的值类型(大部分预定义类型和结构)。
注意:不能使用指针处理类,否则将会破坏堆中.net运行库为垃圾收集器维护的与类相关的信息。
垃圾收集器可以访问的数据类型为托管类型,而指针只能声明指向非托管类型,因为垃圾收集器不能处理他们。
145、指针类型--》整数类型 显式 目的在于显示地址。
指针,在32位机器上,仅能转换为uint、long和ulong,否则溢出。
      在64位机器上,仅能转换为ulong,否则溢出。
注意:使用指针的地方,必须自己控制是否会溢出。即使使用checked检查溢出,溢出发生也不会抛出异常的。
146、指针类型之间可以显式转换。
147、void *指针类型,主要用于调用需要void *类型参数的win api。
148、指针的算术运算。
149、sizeof运算符。
注意:sizeof仅用于值类型,且必须用于不安全的代码。

 

posted on 2011-10-19 09:13  Mr__BRIGHT  阅读(1315)  评论(0编辑  收藏  举报

导航