博文
C# 程序员参考--XML 文档教程(2006-09-03 18:18:00)
摘要:本教程展示如何使用 XML 将代码存档。
教程
C# 提供一种机制,供开发人员使用 XML 将其代码存档。在源代码文件中,以下代码行可以作为注释处理并放在文件中:以 /// 开始的行;在用户定义的类型(如类、委托或接口)、某成员(如字段、事件、属性或方法)或某命名空间声明之前的行。
示例
下面的示例提供对某个已存档的类型的基本概述。若要编译该示例,请键入以下命令行:csc XMLsample.cs /doc:XMLsample.xml
这将创建 XML 文件 XMLsample.xml,您可以在浏览器中或使用 TYPE 命令查看该文件。// XMLsample.cs
// compile with: /doc:XMLsample.xml
using System;
/// <summary>
/// Class level summary documentation goes here.</summary>
/// <remarks>
/// Longer comments can be associated with a type or member
/// through the remarks tag</remarks>
public class SomeClass
{
/// <summary>
/// Store for the name property</summary>
private string myName = null;
/// <summary>
/// The class constructor. </summary>
public SomeClass()
{
// TODO: Add Constructor Logic here
}
/// <summary>
/// Name property </summary>
/// <value>
/// A value tag is used to describe the property value&......
C# 程序员参考--条件方法教程(2006-09-03 18:18:00)
摘要:本教程演示条件方法,它们提供一种功能强大的机制,通过它可以根据是否定义了预处理器符号来包括或省略方法调用。
示例文件
请参见“条件方法”示例以下载和生成本教程中讨论的示例文件。
教程
条件方法使开发人员能够创建这样的方法,可将对这些方法的调用放在代码中,然后编译期间根据预处理符号包括或省略这些调用。
假定您想在调试版本中启用某些断言代码,而在发布版本中禁用它们。在 C++ 中,有不止一种方法可以将此功能包含到您的代码中,例如:
使用 #ifdef 同时定义宏的调试版本和发布版本。调试版本调用跟踪代码,而发布版本不执行任何操作。由于 C# 不支持宏,该方法行不通。
具有正在被调用的代码的两个实现。即,在调试版本中,具有完全功能;而在发布版本中,具有方法的空存根 (stub)。然后,用户在链接项目时选择包括哪一个实现。该方法的问题是,发布版本包含对空方法的调用,并且配置较复杂。
C# 条件方法为该问题提供了简单的解决方案,类似于上面列出的第一种方法。该操作有两个基本机制:
直接在源代码中用 #define 定义预处理标识符。
通过 /define 选项 (/d) 在 C# 命令行上定义预处理标识符。下面的示例中使用该方法。
条件方法用于“.NET Framework”中。System.Diagnostics 命名空间包含许多支持应用程序中的跟踪和调试的类。使用 System.Diagnostics.Trace 和 System.Diagnostics.Debug 类向应用程序添加复杂的跟踪和调试(使用条件方法可从发布版本编译掉的功能)。
下面的示例展示如何使用条件方法实现非常简单的跟踪机制。System.Diagnostics.Trace 提供的跟踪机制复杂得多,但它使用下面的基本机制提供该功能。
示例
本示例由两个源文件组成:第一个文件是提供跟踪机制的库,第二个文件是使用该库的客户程序。
文件 #1:创建条件方法
下面的代码展示了一个简单的库,它提供向系统控制台显示跟踪消息的跟踪机制。客户可以将跟踪调用嵌入代码,然后可以通过在自己的编译阶段中定义符号来控制是否调用跟踪。// CondMethod.cs
// compile with: /target:library /d:DEBUG
using System; ......
C# 程序员参考--显式接口实现教程(2006-09-03 18:15:00)
摘要:本教程演示如何显式实现接口成员以及如何从接口实例访问这些成员。
教程
实现接口的类可以显式实现该接口的成员。当显式实现某成员时,不能通过类实例访问该成员,而只能通过该接口的实例访问该成员。本教程包含两个示例。第一个示例阐释如何显式实现和访问接口成员。第二个示例展示如何实现具有相同成员名的两个接口。
示例 1
本示例声明一个 IDimensions 接口和一个 Box 类,该类显式实现接口成员 Length 和 Width。通过接口实例 myDimensions 访问这些成员。// explicit1.cs
interface IDimensions
{
float Length();
float Width();
}
class Box : IDimensions
{
float lengthInches;
float widthInches;
public Box(float length, float width)
{
lengthInches = length;
widthInches = width;
}
// Explicit interface member implementation:
float IDimensions.Length()
{
return lengthInches;
}
// Explicit interface member implementation:
float IDimensions.Width()
{
return widthInches;
}
public static void Main()
{
// Declare a class instance "myBox":
Box myBox = new Box(30.0f, 20.0f);
// Declare an interface instance "myDimensions":
IDimensions myDimensions = (IDimensions) my......
C# 程序员参考--事件教程(2006-09-03 18:15:00)
摘要:本教程展示如何在 C# 中声明事件、调用事件和挂接到事件。
教程
C# 中的“事件”是当对象发生某些有趣的事情时,类向该类的客户提供通知的一种方法。事件最常见的用途是用于图形用户界面;通常,表示界面中的控件的类具有一些事件,当用户对控件进行某些操作(如单击某个按钮)时,将通知这些事件。
但是事件未必只用于图形界面。事件为对象提供一种通常很有用的方法来发出信号表示状态更改,这些状态更改可能对该对象的客户很有用。事件是创建类的重要构造块,这些类可在大量的不同程序中重复使用。
使用委托来声明事件。如果您尚未学习“委托教程”,您应先学习它,然后再继续。请回忆委托对象封装一个方法,以便可以匿名调用该方法。事件是类允许客户为其提供方法(事件发生时应调用这些方法)的委托的一种方法。事件发生时,将调用其客户提供给它的委托。
除声明事件、调用事件和与事件挂钩的示例以外,本教程还介绍下列主题:
事件和继承
接口中的事件
.NET Framework 指南
示例 1
下面的简单示例展示一个 ListWithChangedEvent 类,该类类似于标准的 ArrayList 类,而且,每当列表内容更改时,该类均调用 Changed 事件。这样一个通用用途的类可在大型程序中以多种方式使用。
例如,某字处理器可能包含打开的文档的列表。每当该列表更改时,可能需要通知字处理器中的许多不同对象,以便能够更新用户界面。使用事件,维护文档列表的代码不需要知道需要通知谁,一旦文档列表发生了更改,将自动调用该事件,正确通知每个需要通知的对象。使用事件提高了程序的模块化程度。// events1.cs
using System;
namespace MyCollections
{
using System.Collections;
// A delegate type for hooking up change notifications.
public delegate void ChangedEventHandler(object sender, EventArgs e);
// A class that works just like ArrayList, but sends event
// notificati......
C# 程序员参考--委托教程(2006-09-03 18:14:00)
摘要:本教程演示委托类型。它说明如何将委托映射到静态方法和实例方法,以及如何组合委托(多路广播)。
教程
C# 中的委托类似于 C 或 C++ 中的函数指针。使用委托使程序员可以将方法引用封装在委托对象内。然后可以将该委托对象传递给可调用所引用方法的代码,而不必在编译时知道将调用哪个方法。与 C 或 C++ 中的函数指针不同,委托是面向对象、类型安全的,并且是安全的。
委托声明定义一种类型,它用一组特定的参数以及返回类型封装方法。对于静态方法,委托对象封装要调用的方法。对于实例方法,委托对象同时封装一个实例和该实例上的一个方法。如果您有一个委托对象和一组适当的参数,则可以用这些参数调用该委托。
委托的一个有趣且有用的属性是,它不知道或不关心自己引用的对象的类。任何对象都可以;只是方法的参数类型和返回类型必须与委托的参数类型和返回类型相匹配。这使得委托完全适合“匿名”调用。
注意 委托是在调用方的安全权限下运行而不是声明方的权限下运行。
此教程包括两个示例:
示例 1 展示如何声明、实例化和调用委托。
示例 2 展示如何组合两个委托。
此外,还讨论以下主题:
委托和事件
委托与接口
示例 1
下面的示例阐释声明、实例化和使用委托。BookDB 类封装一个书店数据库,它维护一个书籍数据库。它公开 ProcessPaperbackBooks 方法,该方法在数据库中查找所有平装书,并为每本书调用一个委托。所使用的 delegate 类型称为 ProcessBookDelegate。Test 类使用该类输出平装书的书名和平均价格。
委托的使用促进了书店数据库和客户代码之间功能的良好分隔。客户代码不知道书籍的存储方式和书店代码查找平装书的方式。书店代码也不知道找到平装书后将对平装书进行什么处理。// bookstore.cs
using System;
// A set of classes for handling a bookstore:
namespace Bookstore
{
using System.Collections;
// Describes a book in the book list:
public struct Book
{
......
C# 程序员参考--运算符重载教程(2006-09-03 18:13:00)
摘要:本教程演示用户定义的类如何重载运算符。
示例文件
请参见“运算符重载”示例以下载和生成本教程中讨论的示例文件。
教程
运算符重载允许为运算指定用户定义的运算符实现,其中一个或两个操作数是用户定义的类或结构类型。本教程包含两个示例。第一个示例展示如何使用运算符重载创建定义复数加法的复数类。第二个示例展示如何使用运算符重载实现三值的逻辑类型。
示例 1
本示例展示如何使用运算符重载创建定义复数加法的复数类 Complex。本程序使用 ToString 方法的重载显示数字的虚部和实部以及加法结果。// complex.cs
using System;
public struct Complex
{
public int real;
public int imaginary;
public Complex(int real, int imaginary)
{
this.real = real;
this.imaginary = imaginary;
}
// Declare which operator to overload (+), the types
// that can be added (two Complex objects), and the
// return type (Complex):
public static Complex operator +(Complex c1, Complex c2)
{
return new Complex(c1.real + c2.real, c1.imaginary + c2.imaginary);
}
// Override the ToString method to display an complex number in the suitable format:
public override string ToString()
{
return(String.Format("{0} + {1}i", real, imaginary));
}
public static void......
C# 程序员参考--用户定义的转换教程(2006-09-03 18:13:00)
摘要:本教程展示如何定义转换以及如何在类或结构之间使用转换。
示例文件
请参见“用户定义的转换”示例以下载和生成本教程中讨论的示例文件。
教程
C# 允许程序员在类或结构上声明转换,以便可以使类或结构与其他类或结构或者基本类型相互进行转换。转换的定义方法类似于运算符,并根据它们所转换到的类型命名。
在 C# 中,可以将转换声明为 implicit(需要时自动转换)或 explicit(需要调用转换)。所有转换都必须为 static,并且必须采用在其上定义转换的类型,或返回该类型。
本教程介绍两个示例。第一个示例展示如何声明和使用转换,第二个示例演示结构之间的转换。
示例 1
本示例中声明了一个 RomanNumeral 类型,并定义了与该类型之间的若干转换。// conversion.cs
using System;
struct RomanNumeral
{
public RomanNumeral(int value)
{
this.value = value;
}
// Declare a conversion from an int to a RomanNumeral. Note the
// the use of the operator keyword. This is a conversion
// operator named RomanNumeral:
static public implicit operator RomanNumeral(int value)
{
// Note that because RomanNumeral is declared as a struct,
// calling new on the struct merely calls the constructor
// rather than allocating an object on the heap:
return new RomanNumeral(value);
}
// Declare an explicit conversion from a ......
C# 程序员参考--索引属性教程(2006-09-03 18:12:00)
摘要:本教程展示如何实现使用索引属性的类。索引属性使您可以使用表示类似于数组的若干种不同事物的集合的类。学习本教程以前应完成索引器教程。
示例文件
请参见“索引属性”示例以下载和生成本教程中讨论的示例文件。
教程
假定您要编写一个 Document 类,该类封装非常长的文本章节。为能够方便地实现各种操作(如检查拼写),您可能希望以单词(以及字符)的虚拟数组形式查看文档。
下面的示例展示实现这种类的技术。对于每个“索引属性”,您定义一个嵌套类,该类包含对主类实例的反向引用。主类上的 readonly 字段提供对嵌套类(定义每个虚拟数组)的实例的访问。每个嵌套类定义一个索引器以及其他类似集合的方法(例如 Count 属性)。下面的示例针对“Words”和“Characters”展示这一点。
注意 请慎重使用该技术!仅在使用数组索引操作提供的抽象化能明确阐明使用您的类的代码,并且索引器同时具有“获取”(Get) 和“设置”(Set) 访问器时,才使用该模式。
示例
本示例中定义了 Document 类。使用 Words 和 Characters 这两个索引属性在 Document 对象上执行某些文本操作。// indexedproperty.cs
using System;
public class Document
{
// Type allowing the document to be viewed like an array of words:
public class WordCollection
{
readonly Document document; // The containing document
internal WordCollection(Document d)
{
document = d;
}
// Helper function -- search character array "text", starting at
// character "begin", for word number "wordCount.......
C# 程序员参考--索引器教程(2006-09-03 18:12:00)
摘要:本教程展示 C# 类如何声明索引器以提供对类的类似数组的访问。
示例文件
请参见“索引器”示例以下载和生成本教程中讨论的示例文件。
教程
定义“索引器”使您可以创建作为“虚拟数组”的类。该类的实例可以使用 [] 数组访问运算符进行访问。在 C# 中定义索引器类似于在 C++ 中定义运算符 [],但前者灵活得多。对于封装类似数组的功能或类似集合的功能的类,使用索引器使该类的用户可以使用数组语法访问该类。
例如,假定您想定义一个类,该类使文件显示为字节数组。如果文件非常大,则将整个文件读入内存是不切实际的,尤其在您只想读取或更改少数字节时。通过定义 FileByteArray 类,您可使文件外观类似于字节数组,但读或写字节时,实际执行的是文件的输入和输出。
除下面的示例以外,本教程中还讨论有关“创建索引属性”的高级主题。
示例
本示例中,FileByteArray 类使得像字节数组那样访问文件成为可能。Reverse 类反转文件的字节。可以运行该程序以反转任何文本文件的字节,包括程序源文件本身。若要将反转的文件更改回正常状态,请在同一文件上再次运行该程序。// indexer.cs
// arguments: indexer.txt
using System;
using System.IO;
// Class to provide access to a large file
// as if it were a byte array.
public class FileByteArray
{
Stream stream; // Holds the underlying stream
// used to access the file.
// Create a new FileByteArray encapsulating a particular file.
public FileByteArray(string fileName)
{
stream = new FileStream(fileName, FileMode.Open);
}
// Close the stream. This shou......
C# 程序员参考--结构教程(2006-09-03 18:11:00)
摘要:本教程介绍结构的语法和用法。它还涉及类与结构之间的重大差异。
示例文件
请参见“结构”示例以下载和生成本教程中讨论的示例文件。
教程
此教程包括两个示例。第一个示例向您展示如何声明和使用结构,而第二个示例演示向方法传递实例时结构和类之间的差异。还向您介绍下列主题:
结构与类
堆还是堆栈?
构造函数和继承
结构上的属性
示例 1
本示例声明一个结构,它有三个成员:一个属性、一个方法和一个私有字段。本示例创建该结构的一个实例,并将其投入使用:// struct1.cs
using System;
struct SimpleStruct
{
private int xval;
public int X
{
get
{
return xval;
}
set
{
if (value < 100)
xval = value;
}
}
public void DisplayX()
{
Console.WriteLine("The stored value is: {0}", xval);
}
}
class TestClass
{
public static void Main()
{
SimpleStruct ss = new SimpleStruct();
ss.X = 5;
ss.DisplayX();
}
}
输出The stored value is: 5
结构与类
结构可能看似类,但存在一些重要差异,应引起注意。首先,类为引用类型,而结构为值类型。使用结构,您可以创建行为类似内置类型的对象,同时享有它们的好处。
堆还是堆栈?
在类上调用“新建”(New) 运算符时,它将在堆上进行分配。但是,当实例化结构时,将在堆栈上创建结构。这样将产生性能增益。而且,您不会像对待类那样处理对结构实例的引用。您将直接对结构实例进行操作。鉴于此原因,向方法传......