`
feiliboos
  • 浏览: 659544 次
文章分类
社区版块
存档分类
最新评论

读书笔记:C#高级编程&.net 3.0(部分一)

 
阅读更多

总结一:第一部分
c#语言
这章共有12小节分别为:
1.net体系结构
2.c#基本语法
3.对象和类型
4.继承
5.数组
6.运算符和强制类型转换
7.委托和事件
8.字符串和正则表达式
9.泛型
10.集合
11.内存管理和指针
12.自定义特性和反射

内容到是不少,分的也很细腻.一章学下来也让我这只小菜鸟对c#语言有了感性的认识.
下面就上面12节涉及到的知识做个小结.例子都是在控制台应用程序下编写的.

.net体系结构:
这节主要是感性的介绍了下.NET的发展历程.从最初的测试1.0版到现在的3.5,并且还描述了
在.net平台上运行的MSIL语言(这个我也不太清楚).MSIL语言是.net的核心部分,c#的源代码
是直接编译成MSIL语言的.然后在通过.net的作用把MSIL语言编译成机器语言.微软采取这种
编译机制目的就是实现跨语言开发,实现多个不同的语言在.net上实现无缝的连接.这点微软
基本上做到了目前.net支持的语言有很多不过我现在知道有:msvc++,vb.net,c#,j++,j#,delphi.
呵呵,微软的开发速度还真是快,现在已经推出了.net框架framework3.0,听说3.5已经开始测试了,
呵呵,这些都是些激动人心的消息!framewoks3.0支持WCF,WPF(不知道这两个是什么),对了还有frameworks2.0
的ajax.呵呵,这节就说这些吧.

c#语法基础
这节涉及的都是c#的基本功,比如说c#定义变量的语法,流控制的语法,运算符,预定义的数据类型,
枚举,数组,命名空间,c#SDK工具的使用.
内容到是蛮多的,不过没什么新的内容,如果大家熟悉任何一门语言的话,在转过来学习c#都会觉得比较轻松.
这就是c#语言的魅力,学习成本低.

c#定义变量的语法
int number;
象上面那样要定义的变量类型放在前面,变量的名称放在后面(变量名要符合变量命名规则),当然不要忘记加";"号.
就这么个简单的句子你就定义了一个叫number的int类型的变量.

流控制语法
所谓流控制就是控制程序的执行走向,程序在执行中肯定会遇到单项选择,多项选择,循环,循环中断(break),循环跳过继续(continue),
goto语句.下面我就来一一回顾:
单项选择--类似我们口语中的是/否语句.给你个是否问句,然后判断你回答的结果做出判断.
例如:
int number=0;
if(number=0)
{
Console.WriteLine("number is 0");
}
else
{
Console.WriteLine("number is not 0");
}
把他回归到我们熟悉的口语就是:number的值是否为0?然后提问者根据回答者的回答做出相应的反应.

多项选择--这里呢得到的答案就可能很多,我们通常是对最有可能的几种情况做出处理,然后设定个默认状态来处理为做处理的情况
例如:
int number;
number=int.Parse(Console.ReadLine());
switch(number)
{
case 1:
Console.WriteLine("number equal 1");
break;//重要,必须加
case 2:
Console.WriteLine("number equal 2");
break;
default:
Console.WriteLine("number is other");
break;
}
这里呢要注意的一些内容为:必须加上break如果不加上的话,会得到意料之外的结果.举个例子:如果number的值为1,但我在case 1:语句块
中没加break,那结果是什么呢,结果就是除了你 能得到你想要的 "number equal 1",并且还能得到这两句"number equal 2","number is other"
这是为什么呢,其实细想下也不难理解:把多条件选择理解成在个类试奔驰车标志的公路上,我们在员的中心点.一开始我们有3条路可以选择,随便
选一条一直开到底,本来到底了就应该停止了,带是你忘了加break那他就不会停,但又不能发生撞车是吧,那怎么办呢...那就按顺序接着跑下面的路,
在这个例子中,车回按右边的原环行驶,达到第二个目的地.

循环:
c#提供三种循环机制,他们的关键字分别为for,while,do..while.循环嘛无非二种情况,有条件循环,和死循环.
有条件循环就是符合条件就循环,不符合就不循环.死循环也是有条件循环的一个特殊的例子,只不过是,他在循环中的条件是固定不变的.
先看2个例子:
for循环
int i,j;
for(i=1;i<=9;i++)
for(j=1;j<=i;j++)
Console.WriteLine("{0}X{1}={2}",i,j,i*j);
Console.WriteLine();
这段代码运行的结果将是生成个梯形的九九乘法表,用的是for循环

while循环
string input;
While(true)
{
input=Console.ReadLine();
if(input=="exit")
break;
Console.WriteLine("You Input: {0}",input);

}
这段代码运行后不段的接受你的输入并把你的输入显示出来,当输入的内容为exit时中止循环.(死循环)

do..while循环
int number;
do
{
number++;
}while(number<=10)
这段代码会先执行内容语句一次然后在跳到条件检测选项进行选择.符合就在次循环,不符合就跳出.这就是我们通常说的后循环.

continue继续执行
例子
for(int i=0;i<10;i++)
{
if(i=5)
continue;
Console.WriteLine(i);
}
当运行continue后,这次循环跳过,直接重下次循环开始.象这个例子当i等于5时就跳过了,所以在结果中你是找不到"5"的.

运算符:
额..我们就来看看咱们的c#都带了那些运算符.
单目运算符:!,~,++,--
双目运算符:+,-,*,/,%,<<,>>,|,||,&,&&,^,<,<=,>,>=,is,以及一些赋值运算符号
三目运算符:?:

运算符的顺序是先算术后关系最后逻辑,当然可以用()来强制改变运算符的默认执行顺序(强烈推荐)

预定义数据类型:
c#语言定义了我们日常处理中需要的数据结构.不用我们自己去定义,省了不少精力..
预定义数据类型分二类,第一类是值类型,第二类是引用类型.
值类型有:sbyte(有符号),short,int,long,byte,ushort(无符号),uint,ulong,float,double,decimal,bool,char
引用类型有:object,string

枚举(enum):
定义枚举无非就是使变量遍于管理,让作用相同的变量归为一类.它是值类型,在编译中分配在堆栈上.
定义方法
enum testenum
{
test1=1,test2=2,test3=3
}

数组:
数组就是在内存上分配一段连续的存储地址用来存储数据,其定义方法为:int[] dataname;
int[] 表示为整型数组,dataname为数组名。
c#中数组可以定义为多维如int[][]是个二维数组。int[][][]是个三维数组。在c#中所有的数组下标均重0开始计算,
比如我定义一个数组int[5]那他表示有5个元素,它门分别为int[0]~int[4](注意:这点与vb不同)。
可以用GetUpperBound来获取数组的上标,用GetLowerBound来获得数组的下标。(注意:数组在使用前必须要实例子化)
除了可以定义规则的数组还可以定义不规则数组(锯齿数组)比如int[5][]在一维下存在这些列int[1][5],int[2][1]之类
的不规则定义。下面写个比较全面的数组例子:
example:
int[] testarray=new int[5] //使用数组前必须实例子化
for(int i=0;i<5;i++)
int[i]=int.Parse(Console.ReadLine());
int[][] testarray2=new int[2];
testarray2[0]=new int[2]{1,2}; //添加不规则的列
testarray2[1]=new int[5]{1,2,3,4,5}
for(int i=0;i<testarray2.length;i++)
for(int j=0;j<testarray2[i].length;j++)
Console.WriteLine("int[{0}][{1}]={2}",i,j,testarray[i][j]);//输出结果


命名空间:
关键字namespace
命名空间的功能就是把一些相关的类包括起来,便于管理。把类比做从超级市场买来的商品,那么命名空间就是提商品的袋子。

c#SDK基本用法
开关/out: ----文件的生成路径
/t: ----文件的生成类型(library类库,exe可执行文件,winexe:window可执行文件,module没说明的模块)
/doc: -----根据原文件的注释生成说明文档.源代码必须采用相应的注释格式方可顺利生成.
/reference: ------导入引用的命名空间

3对象(class)和结构(struct)
这章主要讨论类和结构的区别.类是引用类型,结构是值类型.结构没有不带参数的构造函数.类和结构都提供构造函数初始化器.
类的实例的存储在堆上,结构的实例存储在堆栈上。
类包含的主要元素为:字段,属性访问器,方法,函数,构造函数,析构函数。下面来个例子声明个类:
example:
namespace mycsharp
{
class showme
{

showme()//构造函数
{
//填加逻辑代码
}
public string myfield;//字段,这个字段是全局字段用public声明的

public string Myfield//属性访问器,它也是全局的
{
get{return myfield;}//得到属性值
set{myfield=value;}//设置属性值
}

void MyMothed(string param)//方法,它是类myclass的私有方法
{
Console.WriteLine("You Input Parameter is:{0}",param);
return;
}

internal string GetName(string firstname,string lastname)
{
return firstname+" "+lastname;

}//函数,它的访问范围是这个命名空间,可以理解为在这个命名空间内(mycsharp),他与public没什么区别

~showme()//析构函数,它在该实例的存储空间被释放前激发,通常用来做收尾工作
{
//逻辑代码
}

}

}

下面来看看类的构造函数,构造函数就是在类生成它的实例的时候激发的.如果把类比做模具的话,实例就是用模具生成的产品,那构造函数
在这个过程扮演什么角色呢,我们完全可以把构造函数理解成:通过机器向模具输入一些条件(温度,湿度,什么的..)然后才得到我们想要的
实例,这就是我们平时常见的同一模板做出的东西不可能完全一样是同样的道理.

c#中有个构造函数初始化器,通过它我们可以按照自己的意愿调用构造函数.
class showme
{
private string temp;
/*这里有三个构造函数,它们通过重载实现(三个函数都同名)*/
showme(){temp+="没参数的构造函数";}:this("1") //构造函数初始化器
showme(string param){temp+="一个参数的构造函数";}:this("1","2")
showme(string param,string param2){temp+="二个参数的构造函数";}

public string GetTemp()
{
return temp;
}

}
在这里我们这样实例化一个类showme test=new showme();虽然调用的是没参数的构造函数,但我们调用GetTemp()的到的结果确是
"二个参数的构造函数一个参数的构造函数没参数的构造函数"
这样我们就达到了修改构造函数的执行顺序了.

结构(strcut):
结构的定义与类相似,包含的元素也一样.但是要注意它不允许有没参数的构造函数
example:
namespace mycsharp
{
struct showme_struct
{

/*showme()//构造函数,没参数,在结构中不被允许
{
//填加逻辑代码
}
*/
public string myfield;//字段,这个字段是全局字段用public声明的

public string Myfield//属性访问器,它也是全局的
{
get{return myfield;}//得到属性值
set{myfield=value;}//设置属性值
}

void MyMothed(string param)//方法,它是类myclass的私有方法
{
Console.WriteLine("You Input Parameter is:{0}",param);
return;
}

internal string GetName(string firstname,string lastname)
{
return firstname+" "+lastname;

}//函数,它的访问范围是这个命名空间,可以理解为在这个命名空间内(mycsharp),他与public没什么区别

~showme()//析构函数,它在该实例的存储空间被释放前激发,通常用来做收尾工作
{
//逻辑代码
}

}

}

在c#2.0中提供了些新的关键字partial(部分类)
使用方法
partial class showme
{
private string test1;

}
partial calss showme
{
private string test2;
}
当编译器编译的时候会把他们当一个类showme来进行编译,得到在类showme里有两个访问类型为private的string类型的字段test1,test2.


第四节继承:
关键字":"
类A继承类B那么类A就获得类B中除标记为private访问域的所有元素的访问权.
class B
{
public string GetB()
{
return "public B method";
}
private stirng GetB_2()
{
return "private B method";
}

}

class A:B
{

}
我们就可以这样用这个类A:A testclass=new A();Console.WriteLine(A.GetB());但方法GetB()并不属于类A.
但这样A testclass=new A();Console.WriteLine(A.GetB_2());就不回成功.因GetB_2用了private来修饰.

当我们继承了一个类后但又想在子类中在声明一与父类签名相同,但功能不同的方法或函数,那我们该怎么办呢.
我们应该使用覆盖(override),使用覆盖有个前提就是被覆盖的方法必须用virtual来修饰.
class B
{
virtual public string GetB()
{
return "public B method";
}
private stirng GetB_2()
{
return "private B method";
}

}

class A:B
{
override public string GetB()
{
return "override B.GetB";
}

}

当父类与子类具有相同的方法签名时在掉用该方法是就会报错,因为编译器不知道该调用哪个方法.如果我们是有目的的掉用的话,
我们可以使用隐藏(new)来轻松达到效果:
class B
{
new public string GetB()
{
return "public B method";
}
private stirng GetB_2()
{
return "private B method";
}

}

class A:B
{
public string GetB()
{
return "A.GetB";
}

}
//二个GetB()方法,但我只想调用类A的GetB()方法.那我们就用new来修饰类B的GetB()方法.
A testA=new A();Console.WriteLine(testA.GetB());
得到的结果就是:"A.GetB".


如果我们想在编写类A的时候引用父类B中的方法,而不是在实例子化后调用(设计面向对象中的动态绑定).那该怎么办呢.
其实用关键字(base)就可以轻松搞定!
class B
{
public string GetB()
{
return "public B method";
}
.....

}

class A:B
{
public string WantGetB()
{
return base.GetB();
}

}
这样我们掉用方法WantGetB();得到的结果也是:"public B Method".

这节还涉及到了抽象类,接口这二个概念
抽象类(abstract)就是定义的类中只要包含一个抽象方法(只有签名,没有实现代码),那么这个类就是抽象类.
abstarct class testabstract
{
public string GetResult()
{
return "Test Abstract";
}
abstarct string GetResult_2();

}
这个类就是抽象类,这种类不能实例化,只能被别的类继承,继承它的类必须在代码中实现它的抽象方法.

接口(Interface)
接口的形式和抽象类差不多,在接口里只能定义方法签名,和属性访问器的签名.
它也不允许实例化,但可以被别的类实现,同样的实现他的类必须全部实现接口中的所有方法!
public interface myInterface
{
string GetResult();//方法
string GetFullName//属性访问器
{
get{}
set{}
}

}

接下来就是变量的访问域了
c#中定义了如下的关键字来代表变量的作用域:public,private,internal,protected,internal protected.
public:全局访问
private:私有,定义该变量的内部
protected:继承+私有,出具有私有的特性外,继承他的定义对象也可以访问
internal:友元(不知道为什么叫这个)作用范围--定义该变量的命名空间
internal protected:友元+继承


5数组:
这节也没什么重要的概念,就是介绍了些数组的存储结构,和c#提供的一些处理数组的类。其基本内容都在第二节进行了回顾。
额..这里我想提的就是用foreach跌代对象的一些概念..用foreach跌代下数组从中取出元素,然后分别做处理,原来我也觉的这
样做是天经地义的事情.但是学习了这章后让我改变了这个想法.我们跌代日常使用的数组如int[],string[]之类的,子所以我们
能把foreach用在它们身上是因为它们实现了IEnumerable接口,实现了它的GetEnumerator方法.举个例子你声明个类你再用foreach
来跌代这个类,你看你能得到什么.原来我肯定会说,foreach只能用于数组,这样写是不对了,但明白原理后你回发现,只要你在这个
类里实现了GetEnumerator方法你照样可以通过跌代它,得到元素.吹了那么多,我都有点晕了...些个例子吧..
example:
class testforeach:IEnumerable
{
public IEnumerator GetEnumerator
{
yield return "一";
yield return "二";
yield return "三";
yield return "四";

}


}
好了现在用
foreach(string t in testforeach)
Console.WriteLine(t);
来测试下我的将得到:




呵呵,是吧,除了数组,类也可以跌代,只要实现了IEnumerable接口的GetEnumerator方法都可以用foreach跌代.

6运算符和强制类型转换
这节比较重要的就是运算符重载和强制类型转换符号的重载了..
运算符重载(operator)
看个例子,这里我们重载+号
class name
{
public string first;
public string last;
name(string firstname,stirng lastname)
{
this.first=firstname;
this.last=lastname;

}
override public string ToString()
{
return first+" "+last;
}

}
//重载运算符
public static name operator +(name x,name y)
{
return new name(x.first+y.first,x.last+y.last);
}
这样当两个类型为name的对象相加的时候虽然调用的是运算符+,但运算方式却是按照我们的想法去进行的.
其实.net也有重载了很多运算符,比如:数字+数字=数学运算;字符串+字符串=字符串运算.
还有就是这个段重载操作符的代码,必须放在参与运算类的内部进行定义(任意取一类型),在这里是类name.那我们就应该这么
定义:
class name
{
public string first;
public string last;
name(string firstname,stirng lastname)
{
this.first=firstname;
this.last=lastname;

}
override public string ToString()
{
return first+" "+last;
}
//重载运算符
public static name operator +(name x,name y)
{
return new name(x.first+y.first,x.last+y.last);
}
}

强制类型转换符重载(operator)
平时我们用这样的表达式来达到我们的强制转换的目的
short j;
int i=(int)j;
但当我们使用这样的代码却不允许:
未知类型 i;
int j=(int)i;
难到真的不可以这么做么?...其实不然.我们可以通过重载强制转换运算符来达到目的.
代码:
public static explict(显示)或implict(隐式) operator int(name x)
{
return len(x.ToString());
}
这样一来
name i;
int j=(int)i;
j中存储的数据就是name中的ToString()返回字符串的长度咯..这个你可以自己按需求改变.
这里有个关键点explict显示,implict隐式
显示就这样引用:
name i;
int j=(int)i;
隐式就是这样用(你得声明为implict):
name i;
int j=i;


7委托和事件
.net中的委托类似于c/c++中的指针函数,.net把它封装的更加完整,让我们使用起来很方便.事件呢..
是什么个运行机制呢?事件分二个部分:一个是事件广播器,一个是时间接受器.
先看委托(delegate)
example:
public delegate string ReturnName();
class name
{
public string first;
public string last;
name(string firstname,stirng lastname)
{
this.first=firstname;
this.last=lastname;

}
override public string ToString()
{
return first+" "+last;
}
//重载运算符
public static name operator +(name x,name y)
{
return new name(x.first+y.first,x.last+y.last);
}
}
name temp=new name();
ReturnName returnname=new ReturnName(temp.ToString());
Console.WriteLine("You name is {0}",returnname.InVoke());
委托也可以绑定多个方法(多播委托.注意多播委托只能帮定反回值为void类型的方法).
returnname+=method1;
returnname+=method2;
....
掉用委托后,绑定的方法将按照从上至下的顺序执行.

事件(event)
事件的定义得依赖委托,代码如下:
public delegate string ReturnName();
public static event ReturnName ReturnEvent;

然后在给委托添加绑定方法:ReturnEvent=new ReturnName(methodname);
当我们要触发这个事情的时候通过代码:ReturnEvent();发出事件广播.
事件接受器接受到后执行方法:methodname().
example:
class testEvent
{
public delegate string ReturnName();
public static event ReturnName ReturnEvent;
private string firstname;
private string lastname;
override public string ToString()
{
return firstname+" "+lastname;
}


}
testEvent temp=new testEvent("wang","ming");
temp.ReturnEvent=new temp.ReturnName(temp.ToString());
Console.WriteLine(temp.ReturnEvent());
将得到结果:
wang ming

对了,这节还提到了匿名方法
代码如下(接上面代码):
temp.ReturnEvent=delegate(){return "wang ming";};
Console.WriteLine(temp.ReturnEvent());
结果也是:
wang ming


第八章字符串和正则表达式
我们通常用的string是引用类型,为什么它和别的预定义类型不同呢,在这里它是以类的形式出现,而别的
是以结构的形式出现.
string提供了如下方法供我们处理字符串
Compare:比较字符串逐位比较(ascii码)
CompareOrdinal:同上,带不考虑文化背景
Concat:连接字符串
CopyTo:复制字符串
Format:格式化字符串
indexOf:在给定字符串中查找目标字符串的首次出现位置
IndexOfAny:
Insert:在目标字符串的给定下标插入字符
Join:指定一个连接符号,通过它把给定的字符数组连接起来
LastIndexOfAny:
PadLeft:在字符串的左边通过添加指定字符来填充
PadRight:同上,在右边
Replace:替换,替换目标字符串中的字符
Splict:分割,与join功能相反
SubString:截取字字符串,给顶下标
ToLower:字符串内容全部小写
ToUpper:字符串内容全部大写
Trim:清空字符串两边的空格

字符串也是以数组的形式存储,它的结束位置会放上"/0"的数据,表示这个字符串到尾了.
字符串的存储空间是分配在堆上的.

format:
format支持哪些格式呢?
.net为我们提供了如下格式:
C:货币格式$123.34
D:一般整数435
E:科学记数法4.0E+005
F:有二位小数点的数字423.12
G:一般的数字134.1
N:专用场合的数字1,123.50
P:百分数34,000.00%
X:十进制格式0x1120

正则表达式:
可以查看相关资料

9泛型
泛型是.net2.0推出的一个新特性,使用它不带可以提高代码的运行速度,而且可以很好的提高代码的安全性.
在我们平时使用数据的时候都要经过装箱和拆箱这二个过程(我也不太清楚为什么要这么做).
带使用泛型可以免去这两步,让代码效率更高.

这节介绍了泛型类,泛型方法,泛型委托.
泛型类:
class genericClass<T>//这个T可以为任何类型
{
private T temp;
genericClass(T param)
{
this.temp=param;
}

}
一个泛型类就完成了,有点模板的感觉.
泛型方法(接上面代码):
T ReturnTemp<X>(X param1,X param2)-----------------------------------能这么写吗?
{
X temp;
temp=param1+param2;


}
泛型委托(接上面代码):
delegate T DeleTemp<X>(X param1,X param2)

怎么用呢?
泛型类:
genericClass<int> tempClass=new genericClass<int>();
泛型方法:
ReturnTemp<int>(2,2)
泛型委托:
DeleTemp<int> tempDelegate=delegate(int a){......};

10集合
这节介绍的东东就蛮多了.介绍了一些常用的数据结构:列表(arraylist),栈(stack),队列(queue),链表(LinkList),有序表(SortList),字典(Dictionary)
提到这章就得提到四个接口,它们分别是:IEnumerable,ICollection,IList,IDictionary.
上面介绍的那些.net提供的数据结构也都是实现了它们中的一些接口的方法.
接口IEnumerable:
方法:
GetEnumerator()返回实现IEnumerable接口的类
接口ICollection:
属性:
count集合中元素的数量
IsSynchronized获取一个值,该值指示是否同步对 ICollection 的访问(线程安全)。MSDN上说的,不明白...
SyncRoot 获取可用于同步 ICollection 访问的对象。不明白
方法:
CopyTo() 复制集合
接口IList
属性:
IsFixedSize 获取一个值,该值指示 IDictionary 对象是否具有固定大小。所谓固定大小就是在实例化是指定了大小如new list(20)大小20
IsReadOnly 获取一个值,该值指示 IDictionary 对象是否为只读。用方法AsReadOnly返回一个自读对象???米实现!
Item集合元素访问器,可以通过索引来获取相应元素.
方法:
Add() 添加元素
Clear()清楚集合中的所有元素
Contains() 查看集合是否包含某个元素
IndexOf() 确定 IList 中特定项的索引。按值来确定索引么?
Insert() 在特定索引上插入数据
Remove() 清除值,按内容
RemoveAt()同上,按索引
接口IDictionary
属性:
IsFixedSize 获取一个值,该值指示 IDictionary 对象是否具有固定大小。
IsReadOnly 获取一个值,该值指示 IDictionary 对象是否为只读。
Item
Keys 获取所有键值,返回一个集合Icollection
Values获取所有内容,返回一个集合Icollection
方法:
Add()
Clear()
Contains()
GetEnumerator()
Remove()

弄了这么多概念,现在写些代码来体验下在.net上操纵集合元素的快感吧...
arraylist(IEnumerable,ICollection,IList):
ArrayList tempArray=new ArrayList(20)//设定固定大小
for(int i=0;i<20;i++)
{
tempArray(i)=Console.ReadLine();
}
Console.WriteLine("列表arraylist包含的元素个数为{0}",tempArray.Count);
tempArray.Capacity=30;//重新设置列表的大小
tempArray.TrimExcess();//缩小列表的剩余空间,若以用空间占90%则不做操作...
foreach(string t in tempArray)
Console.WriteLine(t);

stack(IEnumerable,ICollection,ICloneable):
stack<string> tempStack=new stack<string>(10);
for(int i=0;i<10;i++)
tempStack.Push(Console.ReadLine());

Console.WriteLine("这个栈包含的元素有{0}个",tempStack.Count);
for(int i=0;i<10;i++)
Console.WriteLine(tempStack.Pop());

queue(IEnumerable,ICollection,ICloneable):
queue<string> tempQueue=new queue<string>(10);
for(int i=0;i<10;i++)
tempQueue.Enqueue(Console.ReadLine());
for(int i=0;i<10;i++)
Console.WriteLine(tempQueue.Dequeue());


LinkedList<T>(IEnumerable<T>,ICollection<T>,ICollection,IEnumerable,ISerializable,IDeserializationCallback):
介绍LinkedList就得介绍LinkedListNode<T>
LinkedListNode:
属性:
List返回当前所在的LinkedList<T>
Next下个元素的地址
Pervious上个元素的地址
Value当前元素的内容

LinkedList:
属性:
Count
First
Last
方法:
AddAfter()
AddBefore()
AddFirst()
AddLast()
Remove()
RemoveFirst()
RemoveLast()
Clear()
Contains()
Find()
FindLast()


LinkedList是双向链表,用它可以设计出很多东西.这里呢我就用它设计个二维表吧.
员工号(int)员工姓名(string)员工薪水(float)
0001张三3000
0002王五4000
0003赵七1500
0005黑龙8000

LinkedList<int> lnkNum=new LinkedList<int>(4);
LinkedList<string> lnkName=new LinkedList<string>(4);
LinkedList<float> lnkMoney=new LinkedList<float>(4);


sortedList:
它在出入数据的时候根据插入的键值大小,来确定插入的索引顺序.
SortedList<string,string> tempSorted =new SortedList<string,string>(2)
tempSorted.Add("b","bb");tempSorted.Add("a","aa");
虽然("a","aa")是在("b","bb")后插入的,但实际存储上后者在前者前面.也就是说它按键值排了序.


Dictionary:
用法与SortedList类似,也是基于键/值形式的,但不带只动排序功能.

11内存管理和指针
这接主要描述类.net怎么处理内存的机制,以及堆栈和堆的区别.
这里涉及到不安全代码这一概念
在代码中镶嵌不安全必须要用unsafe关键字标记
可以标记类和结构以及它们包含的元素(字段,方法),也可以用
unsafe
{
...........
}
来圈出一部分代码块.
如果源码中包含不安全代码那么必须在编译的时候添加开关
/unsafe


12反射
这章主要描述了自定义特性和反射这两个概念.自定义特性有点象我们平时使用控件的属性样,可以附加信息,这
些信息通过反射来获取.
怎么定义自定义特性呢?
[Serializable]这个自定义特性是.net自带的,表示可以进行序列化.
下面我也来定义一个自定义特性吧:
example
[AttributeUsage(AttributeTargets.Class|AttributeTargets.Method,AllowMultiple=fasle,Inherited=false)]
class myCustom
{
private string firstname;
private string lastname;
private DateTime maketime;
private string groupname;

myCustom(string f,string l)
{
this.firstname=f;
this.lastname=l;
}
myCustom(string f,string l,string m)
{
this.firstname=f;
this.lastname=l;
this.maketime=DateTime.Parse(m);
}
myCustom(string f,string l,string m,string g)
{
this.firstname=f;
this.lastname=l;
this.maketime=DateTime.Parse(m);
this.group=g;

}

public string FullName
{
get{return firstname+" "+lastname;}
}
public DateTime MakeTime
{
get{return maketime;}

}
public string Group
{
get{return group;}
}


}
到这里们我的一个自定义特性就写好了,它的标记是[myCustom].我们来使用下它把.
[myCustom("ghost","bear","1 Aug 2008","GhostGroup")]
class testCustomAttribute
{
[myCustom("ghost","bear")]
public void testMethod()
{
return;
}

}
这里呢,我们对新定义的类testCustomAttribute应用了自己定义的自定义特性,那这么做有什么效果呢?
这样标记的话,当代码编译时会产生myCustom类的二个实例,分别用来做为类testCustomAttribute和方法
testMethod的附加信息,当然要获取这些附加信息还要用到反射技术.
反射的概念是这样定义的:描述了在运行过程中检查和处理程序元素的功能.看起来很让人迷糊,我们还是在
实践中寻求真理吧!
用反射来或去上面myCustom的二个实例的信息.
example:
using System.Reflection //要导入的命名空间

获取类的自定义特性类:
MemberInfo info=typeof(testCustomAttribute)

myCustomAttribute myattribute=(myCustomAttribute).Attribute.GetCustomAttribute(info,typeof(myCustomAttribute));
Console.WriteLine(myattribute.FullName);
Console.WriteLine(myattribute.DateTime);
Console.WriteLine(myattribute.Group);
获取类中元素的自定义特性类:
MemberInfo[] infos=typeof(testCustomAttribute).GetMembers();
foreach(MemberInfo t in infos)
{
foreach(object tt in t.GetCustomAttribute(typeof(myCustomAttribute),false))
{
myCustomAttribute my=tt as myCustomAttribute;
if(my!=null)
{
Console.WriteLine(my.FullName);
Console.WriteLine(my.DateTime);
Console.WriteLine(my.Group);
}
}

}
我现在还不知道用什么方法可以让它们不分开来写。。


代码运行后得到的结果为:
ghostbear
2008年8月1日
GhostGroup
ghostbear
看就这样就简单的获得了这些附加信息,是不有点属性的味道.


分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics