以文本方式查看主题

-  中文XML论坛 - 专业的XML技术讨论区  (http://bbs.xml.org.cn/index.asp)
--  『 Dot NET,C#,ASP,VB 』  (http://bbs.xml.org.cn/list.asp?boardid=43)
----  初探c# (一 至 五)  (http://bbs.xml.org.cn/dispbbs.asp?boardid=43&rootid=&id=75964)


--  作者:卷积内核
--  发布时间:7/10/2009 4:06:00 PM

--  初探c# (一 至 五)
/* 1 绪论

c# 是一种简练,时髦(?),面向对象(object oriented),类型可靠(type-safe)的 编程语言。它(发音:C sharp)是从c/c++发展而来的(?俺觉得更象是java),和c/c++是一个语系。所以,很容易被c/c++的程序员接受。c#的目标是结合Visual Basic的高产和C++质朴的力量。

c#将会是vs7的一分子。vs7还支持vb,vc和标记语言——VBScript和JScript。所有这些语言都会在Next Generation Windows Services (NWGS) platform 中得到支持(c#就需要一个NWGS SDK包,可以在m$的网站上下载)。有了这个东东(NWGS),c#就不需要自己的类库,而使用vc或vb这样一些成熟的库。c#也确实没有自己的类库。

废话完了。

1。1 一个老土的例子(就不能换换吗?)*/
/* idontlikeHelloworld.cs : such a out sample :( */
1: using System;
2: class idontlikeHelloworld
3: {
4: static void Main() {
5: Console.WriteLine("i dont like Hello world");
6: Console.ReadLine();
7: }
8: }
/* 如果俺要出书的话,会考虑换个好点的例子。 ^&^

先说说怎样运行。首先,你需要windows2000!(是的,就是它,请各位不要随地丢果皮—— 整个香蕉丢给俺就可以了。)然后,需要NWGS SDK!(82.4mb,不算很大噢。嘿嘿,好在它没有自己的类库。)安装后,在你的程序所在的目录下键入:

csc idontlikeHelloworld.cs (加上一个回车键)

是不是有点复古的味道?这个操作会在和你的*.cs相同目录下产生一个
idontlikeHelloworld.exe文件。双击它,距可以看见:

i dont like Hello world

回车就可以结束它,非常简单。

不过,也可以这样:把它存成后缀为.c的文件更好
(即:idontlikeHelloworld.c)。这样就可以用vc的IDE进行打字,编辑。vc的
txt editor是最棒的噢(又要vc,NO!!!)。然后:

csc idontlikeHelloworld.c (加上一个回车键)

最终效果是完全一样的。


好,现在分析语法:(c#在语法上完全没有新意 :-| )

1: using System;

using 其实是c++的关键字,在c#中的含义也相仿(就是说俺还不敢100%肯定,抱歉)。using用在另一个关键字namespace之后。还是先看看namespace。
语法(syntax):(from MSDN)

namespace [identifier] { namespace-body }

俺的理解:
  identifier:在这里就是System(请记住:c#和c/c++一样,是区分大小写的!)。System 必须在使用它的范围内是唯一的。即,不能够有第二个System,但可以有system。 而“它的范围”,俺不想详细解说,只有在实践中才可能掌握。而且,初学者根本不必知道!俺也是近来才知道还有个namespace和using。 :)

  在{ namespace-body }中的是真正有用的东东,包括第五行的"nsole.WriteLine"的声明和定义(后面还会提到)。System是由NWGS定义的,咱们只需用(using)它即可。至于System在什么文件里定义,咱就不用管了!交给编译器(就是刚才那个“csc.exe”)去寻找。这就代替了c/c++中的“#include”,可以说是近了一步,避免大量烦人的细节。如果你没学过c/c++,就不用理会。namespace 在后面还会谈到。

2: class idontlikeHelloworld

class:是c语系中另一个关键字“类”。表示一系列的特性(官方说法:属性)和行为方法,有了它你的程序就可以“另类”,创造与别不同的有你特色的东东噢!在这里,俺就定义了“idontlikeHelloworld”。注意:这也是c#强制的,对于每一个可执行的程序都必须有。你想干的事就可以记录在紧跟着你定义的class后面的一对花括号。注意:“{”和“}”一一对应的,“(”和“)”同样。

4: static void Main() {

Main()是本例子第一个动作(行为方法),干的第一件事。它是属于俺定义的idontlikeHelloworld类的方法。并且是c#强制的,是程序的真正开始!在紧跟在它后面的“{}”中的语句顺序,就是程序的运行顺序!本例中只有一行(第六行干嘛用?你可以去掉再编译一次看看),输出一句话。

5: Console.WriteLine("i dont like Hello world");

  非常奇怪,Console(再次提醒:注意大小写)不是俺定义的,从何而来?它其实是属于Systemnamespace 的一个class。WriteLine()是Console类中的一个方法,用来显示一句话(字符串)。
  这里只是用了这个方法的1/18!并且是最简单之一!其他的有机会再说。你也可以用
“Console.WriteLine”在“NGWS SDK Documentaion”中搜索“Console.WriteLine”,记住复选“仅搜索标题”,它会列出19项。好啦,完了!其实,还有“.”没说呢!呵呵...lei si la!!!!

语句不通顺,俺会在以后改进(update),敬请原谅!--“请先用叉子喝汤”


三层交换技术 交换机与路由器密码恢复 交换机的选购 路由器设置专题 路由故障处理手册 数字化校园网解决方案 “.”被称为分隔符(separator),用来连接名字,如上面"Console.WriteLine",就把类和它的方法连接。通过这种方式,咱们就可以使用现成方法集合。这里再回顾一下俺的例子,看看namespace和“.”是如何连用的,还有为什么要使用namespace这个关键字。把例子稍微改一下:

/* idontlikeHelloworld.cs */
1: //using System;
2: class idontlikeHelloworld
3: {
4: static void Main() {
5: System.Console.WriteLine("i dont like Hello world");
6: System.Console.ReadLine();
7: }
8: }

/* 看见了,当俺注销掉“using System;”后,在第五行和第六行加了“System”。程序的结果不会改变。但是,很明显的这样比较罗嗦,所以引入了“namespace”。  其实,class应该可以完成同样的功能。
  不过,设计者可能不想让一个关键字涵盖太多的功能。记得在c向c++发展的时候,引入了“class”,而不是扩展“struct”关键字的功能;又比如“=”只用于赋值,“==”只用于判断相等。这是c/c++和c#在语法上其中一个重要的特点。这样设计的好处很多。有机会再聊噢。
  如果你没学过c/c++,以下的内容可以跳过。c#与c/c++在语法上还是有区别的,比如:
1。c#根本没有“::”;“->”只在程序中很小的片断中。在c#中应采用“.”。
2。c#无须先声明定义,再使用。与java相同。
3。c#取消了用“#include”导入其他的程序文本文件,而采用象征性的句柄引入他人的代码。这样一来,就排除了编程语言间的障碍,方便地使用其它语言编写的库。如“Console”类可以是c#或者是其他任一种语言编写的。



--  作者:卷积内核
--  发布时间:7/10/2009 4:07:00 PM

--  
初探c#(二)自动化的内存管理
手动管理内存需要程序员自行分配和释放内存块。这要求程序员有清晰的头脑和对整个运行过程有十分的把握(好难!)。而c#把程序员从这难以承担的任务中解放出来。在多数的情况下,这种自动内存管理提高代码的质量和程序员的生产力。并且,不会对程序的意图和执行产生幅面的影响(?俺可不相信m$的鬼话)。不过,估计比java的回收站好一点吧。因为c#出道迟嘛(尽胡扯)。
  好了,来看看例子。*/

using System;
public class Stack
{
private Node first = null;
public bool Empty {
get {
return (first == null);
}
}
public object Pop() {
if (first == null)
throw new Exception("Can't Pop from an empty Stack.");
else {
object temp = first.Value;
first = first.Next;
return temp;
}
}
public void Push(object o) {
first = new Node(o, first);
}
class Node
{
public Node Next;
public object Value;
public Node(object value): this(value, null) {}
public Node(object value, Node next) {
Next = next;
Value = value;
}
}
}

class Test
{
static void Main() {
Stack s = new Stack();
for (int i = 0; i < 10; i++)
s.Push(i);
while (!s.Empty)
Console.WriteLine(s.Pop());
}
}
/*
  stack类实现了一系列Node的实例。大家可以看看stack类的Push方法。Node的实例就是在Push方法中创建的。
  就是“first = new Node(o, first);”。请记住这个“new”噢。它就是用来创建类实例的。相关的语法太多,遛到后面用一节详细讲。这里只是要了解自动内存管理(Automatic memory management)好处?!“new”是负责初始化类实例。而在c/c++中释放这些实例要用另一个关键字“delete”。但是在什么时候用delete呢,这通常是很费神的活,老手也会阴沟里翻船。何况是俺呢!但在c#中有不用了。例子里就没有用“delete”。
  当Node的实例不需要时,垃圾收集器(garbage collector)自动销毁它,不用俺操心喽。这点到和java挺像的(可能是抄的)。


三层交换技术 交换机与路由器密码恢复 交换机的选购 路由器设置专题 路由故障处理手册 数字化校园网解决方案   在一个test类里,俺用了一个循环,对stack类的实例的Push方法赋值十次。于是,Push创建了Node的十个实例(instance)。然后用Pop把它们显示出来。其顺序正好与创建的顺序相反。
  这个例子相当的好,是stack的一个典型,也很好的表述了自动内存管理的机制。但也不好懂,好在这一节不是写给毫无基础的网友看的。
  俺自个都花了几分钟看明白,各位大虾更是没问题。

  其实,当显示完了“10”以后,就会有一个Node的实例符合被释放的条件,但垃圾收集器并不一定会这样做。
也就是说,它的行为并不确定(这和java一样,俺猜)。有时候,这种行为会带来一些负面影响。起码是性
能降低。自动内存管理本身也是有问题的。因为它很难管理一些特殊情况。有一些关于java的垃圾收集器的
文章也有提到。m$也不会好得了多少。所以,m$有个不安全代码的术语(unsafe code),用来为高级用户服
务。即,用户可以不采用垃圾收集器。但必须用“unsafe”关键字显式声明之。这样就避免了用户不经意以
外使用不安全代码。下面是一个例子:*/

using System;
class Test
{
unsafe static void WriteLocations(byte[] arr) {
fixed (byte *p_arr = arr) {
byte *p_elem = p_arr;
for (int i = 0; i < arr.Length; i++) {
byte value = *p_elem;
string addr = int.Format((int) p_elem, "X");
Console.WriteLine("arr[{0}] at 0x{1} is {2}", i, addr, value);
p_elem++;
}
}
}
static void Main() {
byte[] arr = new byte[] {1, 2, 3, 4, 5};
WriteLocations(arr);
}
}
/*
俺对这个例子不是很满意,也让俺有点迷惑,有机会再自己写一个。很简单,只是可以用指针了!万岁!
其实,俺对这一节最没有把握了!有不少地方都不能自圆其说!所以,请各位大虾大力批评。*/


--  作者:卷积内核
--  发布时间:7/10/2009 4:09:00 PM

--  
初探c#(三)类型
c#支持两种基本的类型:一种是值(value types),一种是引用(reference types)。值包括简单类型(char、int、和float),枚举(enum)和结构(struct)。引用包括类(class),界面(interface),代表(delegate)和数组阵列(array)。值与引用不同之处在于:值直接存储它的数据内容;而引用存储对象
的引用。是不是粉费解?!打个比方吧。你在某地买了套别墅(好棒噢)。却从未去过,只知道地址,怎么办?你可以坐出租车,司机看了地址就知道怎样走不用你操心。你手里的地址就好像对象的名字,你把它写在程序中,就好像把地址给了司机。司机就是你的编译器,它知道该去哪。你豪华的房子就好比那个NGWS SDK开发包(82mb噢,够豪华了!俺的m啊--就这样烧喽)。房子里有你想要的东东,比如你想写一句话(i dont like Hello world),就好像上面例子,要用到“WriteLine”。于是,你就给出“WriteLine”的地址,比如:“Console.WriteLine”。明白?!俺可累了。zzz... (强打精神)不知道你想到没有,值和引用的区别可以引出一个重要特性。值的变量和变量存储的数据是一一对应的,唯一性。而引用则不然。引用中不同的变量可以引用同一个对象的实例。当其中一个变量改变实例的值时,其他引用这个实例的变量也会受到影响(当然,变量本身并没有改变,即,地址没变)。瞧,变量只是说明存储对象的位置(地址),而不是对象本身。就好像你漂亮的房子被烧了,但你的地址并没有改变,但地址对应的房子就没了。

  也许是别人也有这个地址,他去烧了你的房子!好了,在给个例子:*/

1: using System;
2: class CValue
3: {
4: public int Value = 0;
5: }
6: class Test
7: {
8: static void Main() {
9: int val1 = 0;
10: int val2 = val1;
11: val2 = 123;
12: CValue ref1 = new CValue();
13: CValue ref2 = ref1;
14: ref2.Value = 123;
15: Console.WriteLine("Values: {0}, {1}", val1, val2);
16: Console.WriteLine("Refs: {0}, {1}", ref1.Value, ref2.Value);
17: }
18: }

/* 下面是输出的结果:
Values: 0, 123
Refs: 123, 123

  啊哈,应该粉清楚了吧。变量val1和变量val2互不影响,它们各自有自己的存储空间。而ref2复制了ref1,所以,它们引用了同一个对象的实例。当改变它们其中一个的时候,就会影响到另一个的值。


--  作者:卷积内核
--  发布时间:7/10/2009 4:10:00 PM

--  
初探c#(四)预定义类型
c#提供了一系列预定义类型。它们与c/c++有不少相似的地方。预定义引用类型有object和string。object类型是所有其他类型的基础。

  预定义类型包括符号数、无符号数、浮点、布尔、字符和十进制数。符号数有:

sbyte、short、
int和long;
无符号数有:byte、ushort、uint和ulong;
浮点数有:float和double。

  布尔类型就像一个开关,只有两种状态:true或false。c#对布尔的要求比c/c++严格,与java类似。
  在c#中false不等于0,true也不等于1;false和true都是单独分离出来的一个值。学过c/c++的网友都知道:

*/
int i = 0;
if (i = 0) { // Bug: 应该是 (i == 0)
....
}
/*

是没有问题的。但在c#中会引发一个编译错误(error CS0029: Cannot implicitly converttype 'int' to 'bool')。当然,这样牺牲了一点没有必要的灵活性。我们再也不能这样:

*/
string str;
....
if(str = Console.ReadLine()) {
Console.WriteLine("Your comments are: {0}",str);
....
/*

而必须:

*/
using System;
class BoolTest
{
static void Main() {
string str = Console.ReadLine();//也可以:string str;
if(str == "") // if((str = Console.ReadLine()) == "")
Console.WriteLine("i can't read your comments. Please tell me something! O.K.?");
else
Console.WriteLine("Your comments are: {0}",str);
}
}
/*

三层交换技术 交换机与路由器密码恢复 交换机的选购 路由器设置专题 路由故障处理手册 数字化校园网解决方案   我抄了一张预定义类型的简表供大家参考。

Type Description Examples

object The ultimate base type of all other types object o = new Stack();

string String type; a string is a sequence of string s = "Hello";
Unicode characters

sbyte 8-bit signed integral type sbyte val = 12;

short 16-bit signed integral type short val = 12;

int 32-bit signed integral type int val = 12;

long 64-bit signed integral type long val1 = 12;
long val2 = 34L;

byte 8-bit unsigned integral type byte val1 = 12;
byte val2 = 34U;

ushort 16-bit unsigned integral type ushort val1 = 12;
ushort val2 = 34U;

uint 32-bit unsigned integral type uint val1 = 12;
uint val2 = 34U;

ulong 64-bit unsigned integral type ulong val1 = 12;
ulong val2 = 34U;
ulong val3 = 56L;
ulong val4 = 78UL;

float Single-precision floating point type float value = 1.23F;

double Double-precision floating point type double val1 = 1.23
double val2 = 4.56D;

bool Boolean type; a bool value is either bool value = true;
true or false

char Character type; a char value is a Unicode char value = 'h';
character

decimal Precise decimal type with 28 significant digits decimal value = 1.23M;

你也可以自定义自己的预定义类型,可以这样:

*/
using System;
struct Digit
{...}
class Test
{
static void TestInt() {
int a = 1;
int b = 2;
int c = a + b;
Console.WriteLine(c);
}
static void TestDigit() {
Digit a = (Digit) 1;
Digit b = (Digit) 2;
Digit c = a + b;
Console.WriteLine(c);
}
static void Main() {
TestInt();
TestDigit();
}
}
/*
这一节有点沉闷。:(


--  作者:卷积内核
--  发布时间:7/10/2009 4:10:00 PM

--  
初探c#(五)数组类型(Array types)
1.5 数组类型(Array types)

  数组可以是一维的,也可是多维的。数祖的成员可以是整齐的,也可以是变长(jagged)的。

  一维的数组是最普通,最简单的。这里值给出一个例子,就不多解释了。
*/
using System;
class Test
{
static void Main() {
int[] arr = new int[5];
for (int i = 0; i < arr.Length; i++)
arr[i] = i * i;
for (int i = 0; i < arr.Length; i++)
Console.WriteLine("arr[{0}] = {1}", i, arr[i]);
}
}

/* 结果如下:
arr[0] = 0
arr[1] = 1
arr[2] = 4
arr[3] = 9
arr[4] = 16


三层交换技术 交换机与路由器密码恢复 交换机的选购 路由器设置专题 路由故障处理手册 数字化校园网解决方案   请各位不要催俺!最近确实比较忙。俺手头的资料都不是自个找的。是一个朋友想看中文的,就给俺了一些。但他不喜欢上bbs。 ;( 俺也是边看边译,肯定是错漏百出。所以加了一些个人看法,补充了一些东东作为补救。开始也没想到会有人感兴趣,也没打算写完整。希望大家多提点文章的漏洞。俺好改进。多谢啦!

1.5 数组类型(Array types)

我们还可以比较的看看多维,规则,变长的数组的定义和赋值:*/
class Test
{
static void Main() {
int[] a1 = new int[] {1, 2, 3}; //一维
int[,] a2 = new int[,] {{1, 2, 3}, {4, 5, 6}}; //二维
int[,,] a3 = new int[10, 20, 30]; //三维
int[][] j2 = new int[3][]; //变长
j2[0] = new int[] {1, 2, 3};
j2[1] = new int[] {1, 2, 3, 4, 5, 6};
j2[2] = new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9};
}
}
/*
  上面的例子给出了各种样式的数组。变量a1、a2和a3是规则数组。j2则是变长的数组。
  规则数组很容易就可以计算出它们的长度。比如a3的长度是:10*20*30=6000。相反,变长数组就有点不同,它的每一个维度都必须单独定义。如j2的第一维度是3,第二个是6,第三个是9,所以总长度是:1*3+1*6+1*9=18。

  上面对数组的赋值是严谨的风格,在某种情况下,我们可以简化写法,但我总觉得这种简化应用限制太多,容易出错。在这里就不作介绍了。这里再给一个例子说明函数中的参数如何赋值*/
class Test
{
static void F(long[] arr) {}
static void Main() {
F(new longt[] {1, 2, 3});
}
}


W 3 C h i n a ( since 2003 ) 旗 下 站 点
苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
62.500ms