载入中...

Google
 
 
载入中...
时 间 记 忆
载入中...
最 新 评 论
专 题 分 类
载入中...
最 新 日 志
载入中...
最 新 留 言
载入中...
搜 索
用 户 登 录
载入中...
友 情 连 接
博 客 信 息
载入中...


 
 
载入中...
   
 
 

[c#教程][图文]手把手教你用C#打包应用程序(安装程序)【卸载模块已添加】

 
 

原帖及讨论:<A href="http://bbs.bc-cn.net/dispbbs.asp?boardid=117

 
 
 

[c#教程]C#教程第八课:类的继承

 
 

本节课将介绍C#中的继承,其目的如下:
1.基类的实现

2.类的继承

3.在派生类中初始化基类

4.如何调用基类成员

5.如何覆盖基类成员

继承是面向对象程序设计的主要特征之一,它可以让你重用代码,可以节省程序设计的时间。

1.清单8-1 继承: BaseClass.cs

using System;
public class ParentClass
{
public ParentClass()
{
Console.WriteLine("Parent Constructor.");
}
public void print()
{
Console.WriteLine("I'm a Parent Class.");
}
}

public class ChildClass : ParentClass
{
public ChildClass()
{
Console.WriteLine("Child Constructor.");
}
public static void Main()
{
ChildClass child = new ChildClass();
child.print();
}
}

Output:

Parent Constructor.
Child Constructor.
I'm a Parent Class.

说明


清单8-1演示了两个类的用法。上面的一个类名为ParentClass, main函数中用到的类名为ChildClass。要做的是创建一个使用父类ParentClass现有代码的子类ChildClass。

[1][2][3]下一页

 
 
 

[c#教程]C#教程第七课:类的入门

 
 

本节课将介绍C#中的类,其目的如下:
1.了解构造函数的实现

2.了解实例和静态成员的区别

3.了解析构函数的使用

4.熟悉类的成员类型

在本教程的一开始,你就已经接触到类的用法了。现在,既然已经对类有了感性认识,并知道如何定义一个类,本节课将

定义类的格式是:关键字"Class"后面跟着类名,类名之后的大括号中包含的是类的成员。构造函数没有返回值,且与类同名。清单7-1是一个关于类的例子。

清单 7-1. Example C# Classes: Classes.cs

// Namespace Declaration
using System;
// helper class
class OutputClass {
string myString;
// Constructor
public OutputClass(string inputString) {
myString = inputString;
}

// Instance Method
public void printString() {
Console.WriteLine("{0}", myString);
}
// Destructor
~OutputClass() {
// Some resource cleanup routines
}
}

// Program start class
class ExampleClass {
// Main begins program execution.
public static void Main() {
// Instance of OutputClass
OutputClass outCl = new OutputClass("This is printed by the output class.") { }
// Call Output class' method
outCl.printString();
}
}

说明


1.清单7-1 演示了两个类。

第一个类"OutputClass"包括:一个构造函数,一个实例方法,以及一个析构函数,还包括一个域名"myString"。构造函数是用来初始化类的数据成员的。本例中,OutputClass类的构造函数接收一个字符串参数,并把它拷贝到该类的myString域中。

[1][2]下一页

 
 
 

[c#教程]C#教程第六课:名称空间

 
 

本节课将介绍C#的名称空间。其目的是:
1.了解什么是名称空间。

2.了解如何实现"using"指示符。

3.了解"alias" 指示符的用法。

4.了解名称空间的成员的内容。

在第一课中,你已经在简单的hello程序中看到了"using System;"指示符的使用。该指示符可以让你使用System名称空间中的成员。在第一课中,未及对此作出详细介绍,现在我们来解释一下名称空间的具体用法。一旦学完了本节课,你将了解"using"指示符及其相关内容。

作为C#的元素,名称空间可以用来帮助组织程序的结构,可以避免两套代码集中命名的冲突。在程序代码中,使用名称空间是个良好的编程习惯,因为这有助于重用你的程序代码。

1.清单6-1. The C# Station Namespace: NamespaceCSS.cs

// Namespace Declaration
using System;
// The C# Station Namespace
namespace csharp_station {
// Program start class
class NamespaceCSS {

// Main begins program execution.
public static void Main() {
// Write to console
Console.WriteLine("This is the new C# Station Namespace.");
}
}
}

说明


清单6-1演示了如何创建一个名称空间。把单词"namespace"放在"csharp_station"之前,就创建了一个名称空间。"csharp_station"名称空间内的大括号中包含了成员。

[1][2][3][4]下一页

 
 
 

[c#教程]C#教程第五课:方法

 
 

本节课向你介绍C#的方法,其目的是:
1.了解方法的结构格式

2.了解静态和实例方法之间的区别

3.学会实例对象的使用

4.学会如何调用实例化的对象

5.学会方法的四种参数类型的使用

6.学会使用"this"引用

以往,对于每个程序来说,所有的工作都在Main()方法中实现。这对于功能简单的程序是合适的,因为仅仅用来学习一些概念。有个更好的方法来组织你的程序,那就是使用方法。方法是很有用的,因为方法可以让你在不同的单元中分开设计你的逻辑模块。

方法的结构格式如下:

属性 修饰符 返回值类型 方法名(参数) { 语句 }

我们将在后面的课程中,讨论属性和修饰符。方法的返回值可以是任何一种C#的数据类型,该返回值可以赋给变量,以便在程序的后面部分使用。方法名是唯一,可以被程序调用。为使得你的代码变得更容易理解和记忆,方法的取名可以同所要进行的操作联系起来。你可以传递数据给方法,也可以从方法中返回数据。它们由大括号包围起来。大括号中的语句实现了方法的功能。

1.清单5-1. 一个简单的方法: OneMethod.cs

using System;
class OneMethod {
public static void Main() {
string myChoice;
OneMethod om = new OneMethod();

do {
myChoice = om.getChoice();
// Make a decision based on the user's choice
switch(myChoice) {
case "A":
case "a":
Console.WriteLine("You wish to add an address.");
break;
case "D":
case "d":
Console.WriteLine("You wish to delete an address.");
break;
case "M":
case "m":
Console.WriteLine("You wish to modify an address.");
break;
case "V":
case "v":
Console.WriteLine("You wish to view the address list.");
break;
case "Q":
case "q":
Console.WriteLine("Bye.");
break;
default:
Console.WriteLine("{0} is not a valid choice", myChoice);
}

// Pause to allow the user to see the results
Console.Write("Press any key to continue...");
Console.ReadLine();
Console.WriteLine();
} while (myChoice != "Q"
 
 

 

[c#教程]C#教程第四课:循环控制语句

 
 

本节课将介绍如何使用C#控制语句中的循环语句,本课目的如下:
1.学会"while"循环的用法。

2.学会"do" 循环的用法。

3.学会"for" 循环的用法。

4.学会foreach循环的用法。

5.进一步了解"break"语句的用法。

6.如何使用"continue"语句。

在C#中,使用"goto"语句并不是一个最佳的建立循环的方法。本节课将介绍建立循环的常用方法。

第一个要介绍的语句是while循环语句

1.清单 4-1. While循环:While loop.cs

using System;
class Whileloop {
public static void Main() {
int myInt = 0;

while (myInt
 
 

 

[c#教程]C#教程第三课:选择控制语句

 
 

本节课将介绍如何使用C#选择控制语句,第三课将达到如下几个目的:
1.学会"if"语句的用法。

2.学会"switch"语句的用法。

3.学会在"switch"语句中如何使用"break"语句。

4.理解"goto"语句的正确用法。

在前面几节课中,你所看到的程序都是顺序执行的。你无法控制输入语句,你所能做的就是跟着程序执行直到终止。本节课中,将介绍基于条件进行判断,从而选择进入相应的逻辑分支中去执行。

我们所介绍的第一个选择语句是"if"语句,它有三种基本形式:单条选择, 如果/否则,以及多情形选择。

1.清单3-1. IF语句的格式:IfSelection.cs

using System;
class IfSelect {
public static void Main() {
string myInput;
int myInt;
Console.Write("Please enter a number: ");
myInput = Console.ReadLine();
myInt = Int32.Parse(myInput);
// Single Decision and Action with brackets
if (myInt
 
 

 

[c#教程]C#教程第二课:表达式,类型和变量

 
 

右 逻辑与
 
 

 

[c#教程]C#教程第一课:简单的欢迎程序

 
 

在本文开始写作的时候,虽然商用C# 编译器尚未推出, 但你可以下载微软的.NET works SDK Beta 1.
本节课通过介绍几个简单的程序,使得你对C#有所入门。本节程要达到如下几个目的:
1.理解一个C#程序的基本结构。

2.初步了解"名称空间"的概念。

3.初步了解"类"的概念。

4.了解"Main"方法所做的工作。

5.学会如何读取命令行输入信息。

6.学会使用控制台输入/输出 (I/O)语句。

1.清单1-1. 一个简单的欢迎程序Welcome.cs

// Namespace Declaration
using System;
// Program start class
class WelcomeCSS {
// Main begins program execution.
public static void Main() {
// Write to console
Console.WriteLine("Welcome to the C# Station Tutorial!");
}
}

说明


1.清单1-1中的程序包括四个基本元素:名称空间的声明,类,"Main"方法和语句。

2.本例中对名称空间的声明,表明正在使用"System"这个名称空间。

名称空间内包含了一组可以被C#程序调用的代码。有了"using System;"这个声明,就表明程序可以引用该"System"名称空间内的代码,而无需在每个引用的前面加上"System"。关于这一点,我将在后面专门介绍名称空间的课程中详细介绍。

3.类"class WelcomeCSS"包含了程序所要用到的数据,和所要执行的方法的定义。

同诸如接口和结构这样的元素类似,类在程序中是用来描述对象的,这些元素都将会在后续课程中详细介绍。本例中的类不包含数据,只包含一个方法。该方法定义了该类的行为(或者称为该类所能做的事情)。

[1][2][3]下一页

 
 
 

[c#教程]C#教程第九课:多态性

 
 

本节课将介绍C#的多态性,其目的包括:
1.了解什么是多态性

2.如何定义一个虚方法

3.如何重载一个虚方法

4.如何在程序中运用多态性

面向对象程序设计中的另外一个重要概念是多态性。在运行时,可以通过指向基类的指针,来调用实现派生类中的方法。 可以把一组对象放到一个数组中,然后调用它们的方法,在这种场合下,多态性作用就体现出来了,这些对象不必是相同类型的对象。当然,如果它们都继承自某个类,你可以把这些派生类,都放到一个数组中。 如果这些对象都有同名方法,就可以调用每个对象的同名方法。本节课将向你介绍如何完成这些事情。

1.清单9-1. 带有虚方法的基类:DrawingObject.cs

using System;
public class DrawingObject
{
public virtual void Draw()
{
Console.WriteLine("I'm just a generic drawing object.");
}
}

说明


清单9-1 定义了DrawingObject类。这是个可以让其他对象继承的基类。该类有一个名为Draw()的方法。Draw()方法带有一个virtual修饰符,该修饰符表明:该基类的派生类可以重载该方法。DrawingObject类的 Draw()方法完成如下事情:输出语句"I'm just a generic drawing object."到控制台。

[1][2][3]下一页

 
 
 

[c#教程]VC#2005快速入门之使用while语句

 
 
使用while语句,可以在一个布尔表达式为true的前提下重复运行一个语句。

  while语句的语法如下:

while ( booleanExpression )
statement

  首先会对布尔表达式进行求值,如果为true,就运行语句,然后再次求值布尔表达式。如果表达式仍为true,就再次运行语句,并再次求值表达式。这个过程会反复进行下去,直到布尔表达式求值为false;届时,while语句将退出,并从while之后的第一个语句继续。while语句在语法上与if语句有许多相似的地方(事实上,两者除了关键字不同,语法是完全一样的):

  ·表达式必须是一个布尔表达式。

  ·布尔表达式必须放在圆括号内。

  ·假如首次求值时,布尔表达式为false,语句不会运行。

  ·假如想要在一个while的控制下执行两个或者更多的语句,必须使用大括号将语句分组到一个块中。

  以下while语句向控制台写入0~9的值:

int i = 0;
while (i != 10)
{
 Console.WriteLine(i);
 i ;
}

  所有while语句都应该在某个时候终止。新手常犯的错误是忘记添加一个特别的语句,它最终能造成布尔表达式求值为false并终止循环。在上例中,i ;就属于这种情况。

  注意 while循环中的变量i控制着最终的循环次数。这是非常流行的一个表示法,具有这个作用的变量有时也称为哨兵变量(Sentinel variable)。

  在下面的练习中,准备写一个while循环,它每次从一个源文件中读取一行内容,并将每一行都写入一个文本框中。

  ·使用while语句

  1. 在Visual Studio 2005中打开WhileStatement项目,它位于My Documents文件夹下的\Microsoft Press\Visual CSharp Step by Step\Chapter 5\WhileStatement子文件夹中。

  2. 选择“调试”|“开始执行(不调试)”。

  Visual Studio 2005将生成并运行这个Windows应用程序。应用程序本身是一个简单的文本文件查看器,允许你选择一个文件来显示它的内容。

  3. 单击“Open File”(打开文件)按钮。

  随后会出现“打开”对话框

  4. 切换到My Documents文件夹下的\Microsoft Press\Visual CSharp Step by Step\ Chapter 5\WhileStatement\WhileStatement子文件夹。

  5. 选中Form1.cs文件,再单击“打开”。

  文件名Form1.cs会在小的文本框中显示,但文件的内容没有在大文本框中显示。这是由于我们还没有实现相应的代码来读取源文件的内容,并在大文本框中显示那些内容。下面的步骤将添加这个功能。

  6. 关闭窗体,返回Visual Studio 2005。

  7. 在“代码和文本编辑器”窗口中显示文件Form1.cs的代码,找到openFileDialog_FileOk方法。

  用户在“打开”对话框中选择了一个文件,并在单击“打开”按钮之后,调用该方法。方法的主体目前是:

string fullPathname = openFileDialog.FileName;
FileInfo src = new FileInfo(fullPathname);
filename.Text = src.Name;

/* add while loop here */

  第一个语句声明了一个字符串变量,名为fullPathname,并把它初始化为openFileDialog对象的FileName属性。该语句将fullPathname初始化为“打开”对话框中选择的源文件的完整名称(包括路径)。

  注意 openFileDialog对象是可以从“工具箱”中选取的OpenFileDialog组件的一个实例。利用这个组件提供的方法,你可以向用户显示一个标准的Windows“打开”对话框,让用户从中选择一个文件,并获取所选文件的名称和路径。

  第二个语句声明了一个名为src的FileInfo变量,并把它初始化成代表“打开”对话框中所选文件的一个对象(FileInfo是Microsoft .NET work提供的一个类,可利用它对文件进行各种处理)。

  第三个语句将src变量的Name属性赋给filename控件的Text属性。src变量的Name属性包含了在“打开”对话框中选定的文件名(但无路径信息)。通过此次赋值,文件名会在Windows窗体的filename组件中显示。

  8. 将/* add while loop here */注释替换成以下语句:

source.Text = "";

  source字段是窗体上最大的文本框。把它的Text属性设置成空字符串(""),就可以清除当前显示的任何文本。

  9. 在刚才在openFileDialog_FileOk方法中添加的那一行语句之后,输入以下语句:

TextReader reader = src.OpenText();

  该语句声明了一个名为reader的TextReader变量 (TextReader是.NET work提供的另一个类,它用于从文件这样的来源中读取字符流。该类位于System.IO命名空间中)。OpenFileDialog类提供了OpenText方法,它用于打开用户在“打开”对话框中选择的文件。OpenText方法返回的是一个TextReader对象。上述语句的作用就是将reader初始化为从src.OpenText方法调用中返回的TextReader对象。现在,可以使用reader变量来读取用户选择的文件中的内容。

  10. 在添加到openFileDialog_FileOk方法的上一行语句之后,接着输入以下语句:

string line = reader.ReadLine();
while (line != null)
{
 source.Text = line '\n';
 line = reader.ReadLine();
}

reader.Close();

  上述代码声明了一个名为line的string变量,它用于容纳reader从文件中读取的每一行文本。语句调用reader.ReadLine方法从文件中读取第一行文本。该方法要么返回下一行文本,要么返回一个名为null的特殊值(如果没有更多的行可供读取)。这个调用的结果将赋给line变量。

  while循环开头的布尔表达式检查line变量的值。如果不为null,循环主体就显示读取的文本行,具体的做法是将该行附加到名为source的TextBox控件的Text属性尾部,并在最后添加一个换行符('\n')。TextReader对象的ReadLine方法在读取每一行的时候,会自动剥除换行符,所以需要重新添加这个换行符。随后,while循环将读取下一行文本(这是循环的“更新”语句),然后执行下一次重复。

  循环结束后,调用extReader对象的Close方法来关闭文件。

  提示 熟悉C#语法之后,你会发现while循环中的代码能缩写成下面这样:
 
string line;
while ((line = reader.ReadLine()) != null) { source.Text = line '\n'; }
reader.Close();

  在这种情况下,循环开头的布尔表达式同时还要执行初始化和更新操作。其中将调用ReadLine方法,并将返回值赋给line变量。然而,赋值语句实际会生成一个值——要赋值的表达式的值。所以,可以使用一个关系操作符来比较一个赋值表达式的结果,并最终生成一个布尔结果。在这个例子中,如果所赋的值为null,赋值表达式的值就是null,与null值比较的结果将为true。

  11. 选择“调试”|“
 
 
 

[c#教程]C# 2.0 套接字编程实例初探

 
 

  首先从原理上解释一下采用Socket接口的网络通讯,这里以最常用的C/S模式作为范例,首先,服务端有一个进程(或多个进程)在指定的端口等待客户来连接,服务程序等待客户的连接信息,一旦连接上之后,就可以按设计的数据交换方法和格式进行数据传输。客户端在需要的时刻发出向服务端的连接请求。这里为了便于理解,提到了一些调用及其大致的功能。使用socket调用后,仅产生了一个可以使用的socket描述符,这时还不能进行通信,还要使用其他的调用,以使得socket所指的结构中使用的信息被填写完。

  在使用TCP协议时,一般服务端进程先使用socket调用得到一个描述符,然后使用bind调用将一个名字与socket描述符连接起来,对于Internet域就是将Internet地址联编到socket。之后,服务端使用listen调用指出等待服务请求队列的长度。然后就可以使用accept调用等待客户端发起连接,一般是阻塞等待连接,一旦有客户端发出连接,accept返回客户的地址信息,并返回一个新的socket描述符,该描述符与原先的socket有相同的特性,这时服务端就可以使用这个新的socket进行读写操作了。一般服务端可能在accept返回后创建一个新的进程进行与客户的通信,父进程则再到accept调用处等待另一个连接。客户端进程一般先使用socket调用得到一个socket描述符,然后使用connect向指定的服务器上的指定端口发起连接,一旦连接成功返回,就说明已经建立了与服务器的连接,这时就可以通过socket描述符进行读写操作了。

  .NetWork为Socket通讯提供了System.Net.Socket命名空间,在这个命名空间里面有以下几个常用的重要类分别是:

  ·Socket类 这个低层的类用于管理连接,WebRequest,TcpClient和UdpClient在内部使用这个类。

  ·NetworkStream类 这个类是从Stream派生出来的,它表示来自网络的数据流

  ·TcpClient类 允许创建和使用TCP连接

  ·TcpListener类 允许监听传入的TCP连接请求

  ·UdpClient类 用于UDP客户创建连接(UDP是另外一种TCP协议,但没有得到广泛的使用,主要用于本地网络)

  下面我们来看一个基于Socket的双机通信代码的C#版本

  首先创建Socket对象的实例,这可以通过Socket类的构造方法来实现:

public Socket(AddressFamily addressFamily,SocketType socketType,ProtocolType protocolType);

  其中,addressFamily 参数指定 Socket 使用的寻址方案,socketType 参数指定 Socket 的类型,protocolType 参数指定 Socket 使用的协议。

  下面的示例语句创建一个 Socket,它可用于在基于 TCP/IP 的网络(如 Internet)上通讯。

Socket temp = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

  若要使用 UDP 而不是 TCP,需要更改协议类型,如下面的示例所示:

Socket temp = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

  一旦创建 Socket,在客户端,你将可以通过Connect方法连接到指定的服务器(你可以在Connect方法前Bind端口,就是以指定的端口发起连接,如果不事先Bind端口号的话,系统会默认在1024到5000随机绑定一个端口号),并通过Send方法向远程服务器发送数据,而后可以通过Receive从服务端接收数据;而在服务器端,你需要使用Bind方法绑定所指定的接口使Socket与一个本地终结点相联,并通过Listen方法侦听该接口上的请求,当侦听到用户端的连接时,调用Accept完成连接的操作,创建新的Socket以处理传入的连接请求。使用完 Socket 后,使用 Close 方法关闭 Socket。

  可以看出,以上许多方法包含EndPoint类型的参数,在Internet中,TCP/IP 使用一个网络地址和一个服务端口号来唯一标识设备。网络地址标识网络上的特定设备;端口号标识要连接到的该设备上的特定服务。网络地址和服务端口的组合称为终结点,在 .NET 框架中正是由 EndPoint 类表示这个终结点,它提供表示网络资源或服务的抽象,用以标志网络地址等信息。.Net同时也为每个受支持的地址族定义了 EndPoint 的子代;对于 IP 地址族,该类为 IPEndPoint。IPEndPoint 类包含应用程序连接到主机上的服务所需的主机和端口信息,通过组合服务的主机IP地址和端口号,IPEndPoint 类形成到服务的连接点。

[1][2]下一页

 
 
 

[c#教程]C#中自定义事件的处理

 
 

原帖及讨论:

 
 
 

[c#教程]C#简明教程

 
 
首先讲解一下c#,这里只是粗略的讲解,详细内容请购买相关书籍,或参阅相关文档。c#已经取消了c 中的指针,并且在c 中大量被使用的操作符 (:: -
 
 
 

[c#教程]设计模式之C#实现(四)---- ProtoType

 
 
该模式的意图是:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。那么首先我们应该已经有了一个对象,同时这个对象还支持自我复制(科隆)。在FCL里面我们知道有一个接口专门用来规定这么一个契约,那就是ICloneable接口,该接口只有一个方法Clone,以下MSDN对该接口中对该接口的方法的说明:创建作为当前实例副本的新对象。Clone 既可作为深层副本实现,也可作为浅表副本实现。在深层副本中,所有的对象都是重复的;而在浅表副本中,只有顶级对象是重复的,并且顶级以下的对象包含引用。结果克隆必须与原始实例具有相同的类型或是原始实例的兼容类型。这样一来如果我们想要一个可以自我复制的对象我们可以申明一个类MyClass该类继承接口ICloneable 。

下面我们举一个显示生活中的例子来说明这种方法是普遍存在的的。我想我们可能都知道细胞,细胞是组成机体的最小单位(也许不是),我们知道任何(也许是部分)动物或者植物都是由一个细胞分裂的来的,所以我们可以理解细胞就是一种带有Clone方法的对象,细胞可以不断的调用该方法是我们的机体趋于完整。还可以举一个例子就是病毒,我们都经历过Sars期间,我想如果Sars没有自我复制的功能它就不可能成气候,还有一个人人都要实现的例子就是钱(我不知道是不是恰当),我们可以通过我们的努力使得1块钱变成2块…当然每个人的实现方法不同自然结果也就不同了(不知道是否贴切)。当然上面所据的前两个例子应该都是一种深层副本,因为他一旦被复制就是一个独立的个体,在内存中就是不同的两个地址,而潜表拷贝则不同,表面上看是两个实际上是一个对象的两个引用,也就是实际上他们存在于同一个地址,如果我们改变其中一个那么另一个也会改变。应此我们可以看出应用这种模式的关键就是如何实现Clone的方法。

下面是PROTOTYPE的结构图(来自ROSE2003):




浅拷贝和深拷贝之间的区别:浅拷贝是指将对象中的数值类型的字段拷贝到新的对象中,而对象中的引用型字段则指复制它的一个引用到目标对象。如果改变目标对象中引用型字段的值他将反映在原是对象中,也就是说原始对象中对应的字段也会发生变化。深拷贝与浅拷贝不同的是对于引用的处理,深拷贝将会在新对象中创建一个新的和原是对象中对应字段相同(内容相同)的字段,也就是说这个引用和原是对象的引用是不同的,我们在改变新对象中的这个字段的时候是不会影响到原始对象中对应字段的内容。所以对于原型模式也有不同的两种处理方法:对象的浅拷贝和深拷贝。在FCL中的System命名空间下面有一个浅拷贝的方法叫:MemberwiseClone它是创建当前 Object 的浅表副本。在我们的例子里我想实现一个浅拷贝同时在实现一个深拷贝,这样可以加深理解。

下面是一个浅拷贝的例子:

using System;



namespace Prototype_Shallow{

//因为我们在FCL里面已经有这样的接口所以我们就不定义新的Prototype了

public class ConcretePrototype1 : ICloneable{

private int m_ID;

public int ID{

get{

return this.m_ID;

}

}

public ConcretePrototype1(int id){

this.m_ID = id;

}



public object Clone(){

return this.MemberwiseClone();

}

}



public class ConcretePrototype2 : ICloneable{

private int m_ID;

public int ID

{

get

{

return this.m_ID;

}

}

public ConcretePrototype2(int id){

this.m_ID = id;

}

public object Clone(){

return this.MemberwiseClone();

}

}



}

我们具体的原型都继承了接口ICloneable,同时也实现了该接口里面唯一个一个方法Clone。我们可以在客户端这样创建对象ConcretePrototype1 p1 = new ConcretePrototype1(1); ConcretePrototype1 c1 = (ConcretePrototype1)p1.Clone();首先我们创建了对象p1,接下来我们用通过p1的科隆方法得到了对象c1,这就是一种浅拷贝(因为MemberwiseClone是浅拷贝)。

接下来我们将要实现的是深拷贝,这个一个相对浅拷贝比较困难的工作,我们在拷贝对象的时候不但要拷贝他的数值型字段同时还要复制它的引用字段(有的时候这种工作是非常困难的也许是不可能的)。

namespace Prototype_Deep{

using System.Collections;

public class ConcretePrototype : ICloneable

{

private int m_ID;

public int ID

{

get

{

return this.m_ID;

}

}



private ArrayList m_arrayList = new ArrayList();



public ConcretePrototype(int id)

{

this.m_ID = id;

this.m_arrayList.Add("FirstObject");

this.m_arrayList.Add("SecondObject");

// ...

}



public object Clone()

{

ConcretePrototype c = new ConcretePrototype(this.ID);

c.m_arrayList = new ArrayList();

c.m_arrayList.Add("FirstObject");

c.m_arrayList.Add("SecondObject");

return c;

}



public ConcretePrototype DeepClone(){

return (ConcretePrototype)this.Clone();

}

}

}

该代码显示了如何实现深拷贝,深拷贝的原则就是对于那些引用的字段您需要new(new之前想想是不是能用前面学过的某个创建型的模式实现,这是一个好的习惯)一个出来,然后对该字段里面的对象一一拷贝,这样以来很容易出现循环拷贝,所以说深拷贝要比浅拷贝更难一些。客户端可以通过ConcretePrototype p = new ConcretePrototype(1);ConcretePrototype c = p.DeepClone();来实现克隆一个新的对象。代码如下:

ConcretePrototype p = new ConcretePrototype(1);

ConcretePrototype c = p.DeepClone();

this.richTextBox1.AppendText(p.ToString() ":" p.ID.ToString() "\n");

this.richTextBox1.AppendText(c.ToString() ":" c.ID.ToString() "\n");

c.m_arrayList[0] = "Changed";

for(int i = 0;i
 
 
 

[c#教程]设计模式之C#实现(三)FactoryMethod

 
 

工厂方法的目的很明确就是定义一个用来创建对象的接口,但是他不直接创建对象,而由他的子类来创建,这样一来就将创建对象的责任推迟到了该接口的子类中,创建什么类型的对象由子类来决定,而创建对象的时间由接口来定。因此该模式可以在如下几种情况下使用:1、a class can’t predict the class of objects it must create.2、a class wants its subclasses to specify the objects it creates.3、classes delegate responsibility to one of several helper subclasses,but do not know whick helper subclass is the delegate.在这里我们举一个面包房的例子:面包房的面包机好比一个抽象产品,它是一般的面包,那么我们可以通过特殊的加工工艺使它变成不同种类的面包比如:可以是中国式的面包或者是美国的面包等等。这些特殊种类的面包就是我们的具体产品。而做面包的人(也许是自己)就是Creator(创建者),我们使用我们的方法(工厂方法)来做我们想要的面包。这里的灵活性是不言而喻的,使用面包机可以让我们有更多的选择,只有我们在需要的时候才决定吃那一种面包,这不是很好的一件事情吗,如果没有面包机可能我们只能吃中国面包了。下面我们在举几个我们非常熟悉的FCL(.NET Framrwork Class Labrarly)中的例子,IEnumerable和Ienumerator就是一个Creator和一个Product。另一个例子是:WebRequest 是 .NET work 的用于访问 Internet 数据的请求/响应模型的抽象(在 Visual Basic 中为 MustInherit)基类。使用该请求/响应模型的应用程序可以用协议不可知的方式从 Internet 请求数据。在这种方式下,应用程序处理 WebRequest 类的实例,而协议特定的子类则执行请求的具体细节。请求从应用程序发送到某个特定的 URI,如服务器上的 Web 页。URI 从一个为应用程序注册的 WebRequest 子代列表中确定要创建的适当子类。注册 WebRequest 子代通常是为了处理某个特定的协议(如 HTTP 或 FTP),但是也可以注册它以处理对特定服务器或服务器上的路径的请求。(WebRequest摘自MSDN),这是一种带参数的工厂方法。在FCL里面工厂方法是一种最常见的模式应用。

以上据了一个简单的例子(面包),不知道是不是贴切,我不想重新描写一次该模式,但是再有必要的时候我会加以强调的,下面就用创建型模式的结构图来展现这个模式。


这次我想实现的就是书上的例子,首先我们需要看看我们的环境(上下文),我们为了实现一个迷宫的创建环境所以,这个迷宫的简单结构如下图所示:


为了实现工厂模式来创建迷宫我们有一下的类图,从图中可以看出Creator(MazeGame)里面有很多的工厂方法,用户可以通过它来得到不同的房子(组成迷宫的组件),但是也许我们不知道我们的MazeGame是要创建什么样的Room所以我们可以定义一些子类(现在有两个)用来实现不同的创建工作,Room是组成我们的迷宫的最常见的房子,MazeGame可以产生这样大的房子但是为了满足不同的要求我们可以定义一些特殊的房子比如:带炸弹的房子(是指墙上有炸弹)和可以施魔法的房子(可以对门施魔法)。这样我们可以不改变原来的接口,用MazeGame的子类来完成这些特殊的创建工作,就像下面的图中所表示的一样。


我们把创建的细节推迟到了子类去实现,这样很大程度上提高了程序的韧性,如果我们想创建一个新的房子或者新的门我们可以在不改变原来代码的情况下添加以个MazeGame子类来实现这个想法。但是我觉得这有一个问题为了创建一个新的房子我们必须创建一个新的子类来满足这个要求,这样看起来好像是一对一对的平行的样子。这样会使我们的Creator的子类越来越多,我们可以使用带参数的工厂方法减少这种类的繁殖,下面实现的代码并没有实现这种带参数的工厂方法,网友们可以自己实现。我们只要给MakeWall和MakeDoor传递一个参数来确定创建什么样的Wall和Door,不过我们需要在默认的MazeGame里相应的方法写重裁版本。

[1][2]下一页

 
 
 

[c#教程]设计模式之C#实现(二)---Builder

 
 
设计模式之C#实现---Builder

上次我们学习了创建型模式中的AbstractFactory,这次我们将要介绍一个和它比较像的创建型模式Builder(至于关于Builder的详细内容您可以参考GOF的书,在这里不重复了。)。在GOF的书里Builder的目的是这样的:Separate the construction of a complex object from its representation so that the same construction process can create different representations.在我的程序设计中很难免会使用复杂的对象比如:车的组成、电脑的组成以及人在内。那么我们在创建电脑这个对象的时候我想我们需要一步一步的创建组成电脑的每一部分,先创建CPU对象、Memory对象、HardDisk对象等等。Builder就是这样一种模式用来一步一步的创建对象的每一部分。回忆一下AbstractFactory也是创建一族相关的对象,Builder也是创建一些相关的对象,两者之间的区别很微妙需要在以后的实践中细细体会。

既然文章叫设计模式之C#实现那么肯定少不了代码了,这次我想说的更清楚一些,我打算从如下两个方面来实现,首先我想要直接实现他的结构,也就是我们在下面的图中看到的那些类。接着我将用以个具体的例子或者书上的例子描述一下用来加深理解,希望我的描述可以帮助你更好的学习。

从图上我们可以看出我们的Builder接口中有两个BuilderPart方法A、B,以及一个GetResult方法用来返回创建的对象。将我们用ConcreteBuilder1和ConcreteBuilder1实现接口的时候我们分别在其中加入了一个Private的对象,用来返回建立好的对象,在该实例的内部则是经过了两步才完成了Product对象的初始化。我们建立的Product是由一个Hashtable组成,可以添加和显示自己的每一个部分(就是Hashtable里面的每一个键/值)。好了不废话了看看下面的实现代码,在WinForm中调试通过,你可以参看本系列的AbstractFactory文章找到里面的相关表现对象(RichTextBox)。

代码中有少量的注释是为了更好的理解。

using System;



namespace Builder_Me{



using System.Collections;



// specifies an abstract interface for creating parts of a Product object.

//为创建对象的一个部分指定一个接口

public interface Builder{

void BuildPartA();

void BuildPartB();

Product GetResult();

}



// constructs and assembles parts of the product by impementing the Builder interface.

// defines and keeps track of the representation it creates.

// provides an interface for retrieving the product.

public class ConcreteBuilder1 : Builder{

private Product m_Product;

public void BuildPartA(){

this.m_Product = new Product();

this.m_Product.AddParts("1","PartA");

}

public void BuildPartB(){

this.m_Product.AddParts("2","PartB");

}



public Product GetResult(){

return this.m_Product;

}

}



public class ConcreteBuilder2 : Builder{

private Product m_Product;



public void BuildPartA(){

//必须先调用该方法否则不能实例化对象

this.m_Product = new Product();

this.m_Product.AddParts("3","Part1");

}



public void BuildPartB(){

this.m_Product.AddParts("4","Part2");

}



public Product GetResult(){

return this.m_Product;

}

}



// construct an object using the Builder interface.

public class Director{

public void Construct(Builder builder){

//顺序不能变

builder.BuildPartA();

builder.BuildPartB();

}

}



// represents the complex object under construction.ConcreteBuilder builds

// the product's internal representation and defines the process by which it's

// assembled.

// includes classes that define the constituent parts,including interfaces for

// assembling the parts into the final result.

//要创建复杂的对象该对象我们用Hashtable组合表示。

public class Product{

Hashtable m_Parts = new Hashtable();



public void AddParts(string partKey,string partValue){

this.m_Parts.Add(partKey,partValue);

}



public string ShowSelfParts(){

string strResult = string.Empty;

int i = 1;

foreach(string strTmp in this.m_Parts.Values){

strResult ="Part" i.ToString() ":\t" strTmp "\n";

i ;

}

return strResult;

}

}

}



客户端的代码片断如下:

Director director = new Director();

Builder builder1 = new ConcreteBuilder1();

Builder builder2 = new ConcreteBuilder2();

director.Construct( builder1 );

Product p1 = builder1.GetResult();

this.richTextBox1.AppendText(p1.ShowSelfParts());



director.Construct( builder2 );

Product p2 = builder2.GetResult();

this.richTextBox1.AppendText(p2.ShowSelfParts());

 
 
 

[c#教程]设计模式之C#实现(一)--AbstractFactory(补)

 
 
GOF书中的例子用C#实现的源码:



using System;



namespace AbstractFactory_Maze{

using Maze;



public interface AbstractFactory{

MazeClass MakeMaze();

Wall MakeWall();

Room MakeRoom(int n);

Door MakeDoor(Room oneRoom,Room otherRoom);

}



public class MazeFactory : AbstractFactory{

public MazeClass MakeMaze(){

return new MazeClass();

}

public Wall MakeWall(){

return new Wall();

}

public Room MakeRoom(int n){

return new Room(n);

}

public Door MakeDoor(Room oneRoom,Room otherRoom){

return new Door(oneRoom,otherRoom);

}

}



// this is a client

public class MazeGame{

public MazeClass MazeCreate(AbstractFactory factory){

MazeClass aMaze = factory.MakeMaze();

Room r1 = factory.MakeRoom(1);

Room r2 = factory.MakeRoom(2);

Door aDoor = factory.MakeDoor(r1,r2);



aMaze.AddRoom(r1);

aMaze.AddRoom(r2);



r1.SetSide(Direction.North,factory.MakeWall());

r1.SetSide(Direction.East,aDoor);

r1.SetSide(Direction.South,factory.MakeWall());

r1.SetSide(Direction.West,factory.MakeWall());



r2.SetSide(Direction.North,factory.MakeWall());

r2.SetSide(Direction.East,factory.MakeWall());

r2.SetSide(Direction.South,factory.MakeWall());

r2.SetSide(Direction.West,aDoor);



return aMaze;

}

}



}



namespace Maze{

using System.Collections;



public class MapSite{

public virtual void Enter(){}

}



public enum Direction {North,South,East,West}



public class Room : MapSite{

public string Print(){

string result = "";

for(int i = 0 ;i
 
 
 

[c#教程]设计模式之C#实现(一)--AbstractFactory

 
 
Abstract Factory 读书笔记

意图:

为创建相关的或者相互依赖的对象配置一个借口而不指定他们具体的类。

别名:

Kit

理解:

抽象工厂是一种创建型的模式,它为我们创建对象提供了有效地方法,我们不用直接new对象而是可以为创建对象配置一个接口,该接口定义了如何创建对象的方法。我们还知道抽象工厂创建的对象是一个系列的或者是一族的。该模式的最大特点就是将它的具体创建的任务交给了他的子类也就是具体的类,因此我们将创建对象的时间延迟到了它的子类。我们知道,在设计模式(GOF)的书里说了设计模式是为有一定面向对象基础的开发人员准备的。所以我们都应改知道类和类型之间的区别,在现在的编程语言里接口是最为抽象的数据结构,因此我们将我们的抽象工厂里的AbstractFactoy定义成接口也是很自然的。一个这样的工厂可以创建一族产品是什么意思呢?也就是说这一类产品都有相同的父类或者父接口。在这里我不想重复GOF里面的话关于这些对象之间的协作和结果以及带来的影响等等,这些在《Design Patterns Elements of Resable Object-Oriented Software》本书里可以看到。下面我想用C#实现这个模式来供大家参考。

结构:




通过我们的面向对象的知识我们知道一个父类可以标识一个子类的对象,这也是理解这里的关键,我们在程序里将会用一个抽象类的对象表示一个子类的对象。如上图所示,我们现在有我们有一个IabstractFactoy的接口,该接口的职责就是实现创建对象的工作,我们再有两个具体的工厂ConcreteFactory1和ConcreteFactory2他们就是具体实现接口中的函数他们实现了这两个方法,当然在具体的应用中可能没有两个具体的工厂,在GOF的书中说过在很多情况下我们并没有工厂的抽象接口,大多数情况都是直接使用具体工厂来实现的,在这里我想力图完整的描述书中的结构所以实现也是一样的。好了下面就是我的代码,这段代码显示了我们是怎么在C#中实现AbstractFactory的。我用一个WinForm来测试结构。

实现代码:

using System;



namespace AbstractFactory_Me

{

public interface IAbstractFactory{

IAbstractProductA CreateProductA();

IAbstractProductB CreateProductB();

}



public interface IAbstractProductA{

string ShowSelf();

string ShowOther(IAbstractProductB b);

}

public class ProductA1 : IAbstractProductA{

public ProductA1(){}

public string ShowSelf(){

return this.ToString();

}

public string ShowOther(IAbstractProductB b){

return b.ToString();

}

}

public class ProductA2 : IAbstractProductA{

public ProductA2(){}

public string ShowSelf(){

return this.ToString();

}

public string ShowOther(IAbstractProductB b){

return b.ToString();

}

}



public interface IAbstractProductB{

string ShowSelf();

string ShowOther(IAbstractProductA a);

}

public class ProductB1 : IAbstractProductB{

public string ShowSelf(){

return this.ToString();

}

public string ShowOther(IAbstractProductA a){

return a.ToString();

}

}

public class ProductB2 : IAbstractProductB{

public string ShowSelf(){

return this.ToString();

}

public string ShowOther(IAbstractProductA a){

return a.ToString();

}

}



public class ConcreteFactory1 : IAbstractFactory{



public IAbstractProductA CreateProductA(){

return new ProductA1();

}



public IAbstractProductB CreateProductB(){

return new ProductB1();

}



}



public class ConcreteFactory2 : IAbstractFactory{

public IAbstractProductA CreateProductA(){

return new ProductA2();

}

public IAbstractProductB CreateProductB(){

return new ProductB2();

}

}

public class Client{

public void run(){

IAbstractFactory factory1 = new ConcreteFactory1();

IAbstractProductA a = factory1.CreateProductA();

a.ShowSelf();

IAbstractProductB b = factory1.CreateProductB();

b.ShowSelf();

b.ShowOther(a);

}

}

}

我们在测试的WinForm里面放了一个richTextBox1实例,他用来显示结构。

private void Form1_Load(object sender, System.EventArgs e) {

this.richTextBox1.Clear();

IAbstractFactory factory1 = new ConcreteFactory1();

IAbstractProductA a = factory1.CreateProductA();

IAbstractProductB b = factory1.CreateProductB();



this.richTextBox1.AppendText(a.ShowSelf() "\n");

this.richTextBox1.AppendText(b.ShowSelf() "\n");

this.richTextBox1.AppendText(b.ShowOther(a) "\n");

this.richTextBox1.AppendText(a.ShowOther(b) "\n\n\n");



this.richTextBox1.AppendText(a.GetType().ToString() "\n");

this.richTextBox1.AppendText(b.GetType().ToString() "\n");



}

为了清楚的说明问题我们在生成的对象中使用了ShowSelf和ShowOther的方法用来显示自己和另外一个对象。

 
 
 

[c#教程]C#语言初级入门(3)

 
 
在这最后一个例子中,我们来看看C#的抽象和多态性。首先我们来定义一下这两个新的术语。抽象(Abstract)通过从多个对象提取出公共部分并把它们并入单独的抽象类中实现。在本例中我们将创建一个抽象类Shape(形状)。每一个形状都拥有返回其颜色的方法,不论是正方形还是圆形、长方形,返回颜色的方法总是相同的,因此这个方法可以提取出来放入父类Shape。这样,如果我们有10个不同的形状需要有返回颜色的方法,现在只需在父类中创建一个方法。可以看到使用抽象使得代码更加简短。

   在面向对象编程领域中,多态性(Polymorphism)是对象或者方法根据类的不同而作出不同行为的能力。在下面这个例子中,抽象类Shape有一个getArea()方法,针对不同的形状(圆形、正方形或者长方形)它具有不同的功能。

   下面是代码:


public abstract class Shape {
protected string color;
public Shape(string color) {
this.color = color;
}
public string getColor() {
return color;
}
public abstract double getArea();
}

public class Circle : Shape {
private double radius;
public Circle(string color, double radius) : base(color) {
this.radius = radius;
}
public override double getArea() {
return System.Math.PI * radius * radius;
}
}

public class Square : Shape {
private double sideLen;
public Square(string color, double sideLen) : base(color) {
this.sideLen = sideLen;
}
public override double getArea() {
return sideLen * sideLen;
}
}

/*
public class Rectangle : Shape
...略...
*/

public class Example3
{
static void Main()
{
Shape myCircle = new Circle("orange", 3);
Shape myRectangle = new Rectangle("red", 8, 4);
Shape mySquare = new Square("green", 4);
System.Console.WriteLine("圆的颜色是" myCircle.getColor()
"它的面积是" myCircle.getArea() ".");
System.Console.WriteLine("长方形的颜色是" myRectangle.getColor()
"它的面积是" myRectangle.getArea() ".");
System.Console.WriteLine("正方形的颜色是" mySquare.getColor()
"它的面积是" mySquare.getArea() ".");
}
}

 
 
 

[c#教程]叩开C#之门系列之几个重要名词

 
 
初学者很容易把这些概念搞混淆。先说说项目(Project),通俗的说,一个项目可以就是你开发的一个软件。在.Net下,一个项目可以表现为多种类型,如控制台应用程序,Windows应用程序,类库(Class Library),Web应用程序,Web Service,Windows控件等等。如果经过编译,从扩展名来看,应用程序都会被编译为.exe文件,而其余的会被编译为.dll文件。既然是.exe文件,就表明它是可以被执行的,表现在程序中,这些应用程序都有一个主程序入口点,即方法Main()。而类库,Windows控件等,则没有这个入口点,所以也不能直接执行,而仅提供一些功能,给其他项目调用。

  在Visual Studio.Net中,可以在“File”菜单中,选择“new”一个“Project”,来创建一个新的项目。例如创建控制台应用程序。注意在此时,Visual Studio除了建立了一个控制台项目之外,该项目同时还属于一个解决方案(Solution)。这个解决方案有什么用?如果你只需要开发一个Hello World的项目,解决方案自然毫无用处。但是,一个稍微复杂一点的软件,都需要很多模块来组成,为了体现彼此之间的层次关系,利于程序的复用,往往需要多个项目,每个项目实现不同的功能,最后将这些项目组合起来,就形成了一个完整的解决方案。形象地说,解决方案就是一个容器,在这个容器里,分成好多层,好多格,用来存放不同的项目。一个解决方案与项目是大于等于的关系。建立解决方案后,会建立一个扩展名为.sln的文件。

  在解决方案里添加项目,不能再用“new”的方法,而是要在“File”菜单中,选择“Add Project”。添加的项目,可以是新项目,也可以是已经存在的项目。

  程序集叫Assembly。学术的概念我不想提,通俗的角度来说,一个项目也就是一个程序集。从设计的角度来说,也可以看成是一个完整的模块(Module),或者称为是包(Package)。因此,一个程序集也可以体现为一个dll文件,或者exe文件。怎样划分程序集也是大有文章的,不过初学者暂时不用考虑它。

  命名空间(namespace)是在C 里面就有的概念。引入它,主要是为了避免一个项目中,可能会存在的相同对象名的冲突。这个命名空间的定义,没有特殊的要求。不过基本上来说,为了保证其唯一性,最好是用uri的格式,例如BruceZhang.com。这个命名空间有点像我们姓名中的姓,然后每个对象的名字则是姓名中的名。如果有重复,再国外的命名中,还可以加上middle name。那么名都为勇的,由于姓氏不同也就分开了,或者叫张勇,或者叫赵勇。当然人的姓氏重复者居多,所以我们为命名空间取名时,尽可能的复杂一点。 有许多初学者,常常把一个项目就理解为一个命名空间。其实这两者没有绝对的联系,在项目里我们也可以定义很多不相同的命名空间。但为了用户便于使用,最好在一个项目中,其命名空间最好是一体的层次结构。在Visual Studio里,我们可以在项目中新建一个文件夹,默认情况下,该文件夹下对象的命名空间,应该是“项目的命名空间.文件夹名”。当然,我们也可以在namespace中修改它。

  命名空间和程序集名,都可以在Visual Studio中设置。用鼠标右键单击项目名,就可以弹出如下对话框:


  在图中,Assembly Name就是程序集名,如果经过编译,则为该项目的文件名。而Default Namespace则为默认的命名空间。在开发软件时,我们要养成良好的习惯,在建立新项目后,就将这些属性设置好。一旦设置好了Default Namespace,则以后新建的对象,其命名空间即为该设定的值。至于程序集名,如果是dll文件,建议其名最好与Default Namespace一致。

  实例演练:

  (一)创建控制台应用程序“Hello World!”

  1、打开Visual Studio.Net,选择“File”菜单的“new”,选择“Project”;

  2、选择Visual C# Projects中的“Console Application”,如图所示:


  在Location中,定位你要保存的项目的路径,而名字则为“FirstExample”。该名字此时既是解决方案的名字,同时也是该项目的名字。

  3、用鼠标右键单击项目名,在弹出的对话框中,将Assembly Name命名为HelloWorld,将Default Namespace命名为:BruceZhang.com.FirstExample。

  4、此时Visual Studio中已经建立了一个文件,其名为Class1.cs(如果是Visual Studio 2005,则默认为Program.cs);修改该文件的文件名为HelloWorld.cs,同时修改文件中的namespace,和类名,如下:

namespace BruceZhang.com.FirstExample
{
 ///
 
 
 

[c#教程]C#语言初级入门(1)

 
 
导读

  C#是Microsoft开发的一种新语言,它和C/C 一样强大,和Java一样提供丰富的网络编程支持和自动内存管理,和VB一样简单易用。本文的目的是为尚未接触过C#的程序员介绍这种编程语言,是一个基础的入门教程。
作者:仙人掌工作室
2001-02-20

   原文出处:http://journal.iftech.com/articles/0011_joey_CSharp/
   C#读作“C sharp”,它是Microsoft开发的一种新语言,结合了C/C 的强大功能和Visual Basic的易用性。从最初的语言规范即可看出,C#无论在语法、丰富的Web开发支持还是自动化的内存管理上都和Java非常相似。因此,如果你曾经用过C 或者Java,再来学习C#应该是相当轻松的。

   本文的目的在于为尚未接触过C#的程序员介绍这种编程语言。不论你以前是否用过C/C 或者Java,都可以从本文开始学习C#。本文的唯一假定是你具有某种类型的编程知识(如具有面向对象编程的经验则更好,但并非必须),并拥有某种类型的C#编译器。

   最简单的C#程序

   首先我们来看标准的Hello World程序。用文本编辑器创建一个新文件HelloWorld.cs,把下面的代码放入这个文件:


// 第一个c#程序

class HelloWorld {
static void Main() {
System.Console.WriteLine("Hello World!");
}
}


   现在,在DOS命令窗口进入保存HelloWorld.cs的目录,然后执行:


csc HelloWorld.cs


   该命令编译源代码并生成HelloWorld.exe文件。运行这个执行文件就可以看到:


Hello World!


   下面我们来分析一下这个例子。第一行代码是一行注释,由“//”开始。和C/C 以及Java一样,“//”告诉编译器忽略该行直至结尾为止的内容。C#中的另外一种注释方法是块注释。块注释由“/*”开始,到“*/”结束。

   程序中第二个重要的地方是第四行Main()方法的声明(static void Mian(){)。每一个C#程序都包含一个Main方法,它是程序执行的起点和终点。另外还请注意,HelloWorld类的Main()方法定义成了静态(static)方法。程序的Main方法永远不会是全局的,这意味着Main方法必须包含在类里面,如本例中Main()是在类HelloWorld里面(Main方法也可以包含到结构里面,但一般它总是在类里面)。

   程序中最后一个关键的地方是向控制台输出文本的代码,即“System.Console.WriteLine("Hello World!");”。WriteLine是一个方法,定义于Console类。WriteLine()把文本输出到标准输出设备并换行。Console类包含在System名称空间(类的集合)里面。如果你想避免用“System.Console”的方式来指出Console类的全称,可以在文件的开头加上“using System;”这行代码,以后就可以直接写出“Console.WriteLine("Hello World!");”。

 
 
 

[c#教程]C# 低级Windows API钩子拦截键盘输入

 
 
摘要 在家里,婴儿和其它动物可能会重击你的计算机键盘,致使出现各种无法预言的结果。本文中的这个C#示例应用程序将向你展示如何基于Windows钩子API来实现在击键造成任何危害之前捕获它们。

  一. 简介

  猫和婴儿有很多共同之处。他们都喜欢吃家中养植的植物,都非常讨厌关门。他们也都爱玩弄你的键盘,结果是,你正发送给你的老板的电子邮件可能是以半截句子发送出去的,你的Excel帐户也被加入了一些乱七八糟的内容,并且你还没有注意到,当打开Windows资源管理器时,若干文件已经被移到了回收站!

  其解决方案是,开发一个应用程序实现如下功能:只要键盘处于"威胁状态"你就可以进行切换,并确保任何键盘输入活动都不会造成危害。本文想展示如何使用一种低级Windows API钩子在一个C#应用程序中实现键盘"控制"。下图是本文示例程序的一个运行快照。


  二. 背景

  其实,已经存在许多有关于Windows钩子的文章和示例代码,并且已经有人编写过与本文几乎一样的C 示例程序。然而,当我搜索相应的C#应用程序的源码时,却找到极少的.NET示例,而且没有一个程序能够提供一个方便的自包含的C#类。

  .NET框架能够使你以托管方式来存取你最常使用的键盘事件(通过KeyPress,KeyUp和KeyDown)。遗憾的是,这些事件都不能被用来停止Windows组合键(如Alt Tab或Windows"开始"键),从而允许用户"远离"某一个应用程序。

  本文的想法在操作系统级上捕获键盘事件而不是通过框架级来实现。为此,应用程序需要使用Windows API函数来把它自身添加到应用程序"钩子链"中以监听来自操作系统的键盘消息。当它收到这种类型的消息时,该应用程序能够选择性地传递消息,或者进行正常处理,或者"镇压"它以便不再有其它应用程序(包括Windows)来影响它。本文正是想解释其实现机理。

  然而,请注意,本文中的代码仅适用于基于NT版本的Windows(NT,2000和XP),并且无法使用这个方法来停用Ctrl Alt Delete。有关于如何实现这一点,你可以参考MSDN有关资料。

  三. 使用代码

  为了易于使用,我在本文中提供了两个独立的zip文件。一个仅包含KeyboardHook类,这是本文介绍的重点。另一个是一个完整的微软Visual C# 2005 Express Edition应用程序工程,名叫"Baby Keyboard Bash",它实现显示击键的名字或彩色的形状以响应于击键。

  四. 实例化类

  键盘钩子是通过keyboard.cs中的KeyboardHook类来建立和管理的。这个类实现了IDisposable接口,因此,实例化它的最简单的方法是在应用程序的Main()方法中使用using关键字来封装Application.Run()调用。这将确保只要该应用程序开始即建立钩子并且,更重要的是,当该应用程序结束时立即使这个钩子失效。

  这个类引发一个事件来警告应用程序已经有键被按下,因此主表单能够存取在Main()方法中创建的KeyboardHook实例就显得非常重要;最简单的方法是把这个实例存储在一个公共成员变量中。

  KeyboardHook提供了三种构造器来启用或禁用某些设置:

  · KeyboardHook():捕获所有击键,没有任何内容传递到Windows或另外的应用程序。

  · KeyboardHook(string param):把参数串转换为Parameters枚举中的值之一,然后调用下面的构造器:

  · KeyboardHook(KeyboardHook.Parameters enum):根据从Parameters枚举中选择的值的不同,分别启动下列设置:

   o Parameters.AllowAltTab:允许用户使用Alt Tab切换到另外的应用程序。

   o Parameters.AllowWindowsKey:允许用户使用Ctrl Esc或一种Windows键存取任务栏和开始菜单。

   o Parameters.AllowAltTabAndWindows:启用Alt Tab,Ctrl Esc和Windows键。

   o Parameters.PassAllKeysToNextApp:如果该参数为true,那么所有的击键将被传递给任何其它监听应用程序(包括Windows)。

  当击键继续被键盘钩子捕获时,启用Alt Tab和/或Windows键允许实际使用该计算机者切换到另一个应用程序并且使用鼠标与之交互。PassAllKeysToNextApp设置有效地禁用了击键捕获;这个类也是建立一个低级键盘钩子并且引发它的KeyIntercepted事件,但是它还负责把键盘事件传递到另一个监听程序。

  因此,实例化该类以捕获所有击键的方法如下:

public static KeyboardHook kh;
[STAThread]
static void Main()
{
 //其它代码
 using (kh = new KeyboardHook())
 {
  Application.Run(new Form1());
 }

[1][2][3][4]下一页

 
 
 

[c#教程]C#语言初级入门(2)

 
 
下面这个例子示范如何创建和使用用户定义的类以及如何创建动态链接库。利用文本编辑器创建两个文件。第一个是Apple.cs,内容如下:
public class Apple {

private string variety = "";

public Apple(string appleVariety) {
this.variety = appleVariety;
}

public void outputVariety() {
System.Console.WriteLine(variety);
}

}


   第二个文件是Example2.cs,内容如下:


class Example2 {

static void Main() {
Apple mac = new Apple("Macintosh ");
Apple gra = new Apple("Granny Smith");
Apple cor = new Apple("Cortland");
mac.outputVariety();
gra.outputVariety();
cor.outputVariety();
}
}


   首先,我们定义了一个新的用户定义类,名字为Apple。虽然Apple类并不一定要放到独立的文件中,但把每个类都放到自己独立的文件中是一个好的面向对象编程习惯,有助于简化组织和管理。我们为Apple类的声明加上了public修饰符(public class Apple),这样其他类就可以创建Apple类的实例。

   下一行代码定义了实例变量variety。使用了修饰符private之后,只有在Apple类的内部才可以直接访问variety变量。这是一种常见的面向对象编程习惯,称为封装。封装之后,对象的工作细节对于对象的用户来说就隐藏不可见了。你现在正使用的键盘就是封装在现实世界中一个很好的例子。我们并不完全了解键击如何发送到控制器(我们之中的大多数都不知道),但只要理解它的接口如何运作就可以了。例如我们知道,打开文本编辑器,按下键盘上的“

 
 
 

[c#教程]C#教程第十课:属性

 
 

本节课将介绍C#的属性,其目的包括:
1.理解什么是属性

2.如何实现属性

3.创建一个只读属性

4.创建一个只写属性

属性是C#中独具特色的新功能。通过属性来读写类中的域,这具有一定的保护功能。在其它语言中,这是通过实现特定的getter和setter方法来实现的。C#的属性具有保护功能,可以让你就象访问域一样访问属性。要了解属性的用法,我们先来看看如何用传统的方法对域进行封装。

1.清单 10-1. 传统的访问类的域的例子:Accessors.cs

using System;
public class PropertyHolder
{
private int someProperty = 0;
public int getSomeProperty()
{
return someProperty;
}
public void setSomeProperty(int propValue)
{
someProperty = propValue;
}
}

public class PropertyTester
{
public static int Main(string[] args)
{
PropertyHolder propHold = new PropertyHolder();
propHold.setSomeProperty(5);
Console.WriteLine("Property Value: {0}", propHold.getSomeProperty());
return 0;
}
}

说明


1.清单 10-1 演示了用传统方法访问类的域的例子。

PropertyHolder类有个我们感兴趣的域someProperty, PropertyHolder类带有两个方法:getSomeProperty和setSomeProperty。getSomeProperty方法返回someProperty域的值。SetSomeProperty方法设置域someProperty的值。

[1][2][3][4]下一页