博文
C# 语言规范--1.2 类型(2006-09-03 18:27:00)
摘要:C# 支持两种类型:“值类型”和“引用类型”。值类型包括简单类型(如 char、int 和 float)、枚举类型和结构类型。引用类型包括类 (Class) 类型、接口类型、委托类型和数组类型。
值类型与引用类型的区别在于值类型的变量直接包含其数据,而引用类型的变量则存储对象引用。对于引用类型,两个变量可能引用同一对象,因此对一个变量的操作可能影响另一个变量所引用的对象。对于值类型,每个变量都有自己的数据副本,对一个变量的操作不可能影响另一个变量。
示例using System;
class Class1
{
public int Value = 0;
}
class Test
{
static void Main() {
int val1 = 0;
int val2 = val1;
val2 = 123;
Class1 ref1 = new Class1();
Class1 ref2 = ref1;
ref2.Value = 123;
Console.WriteLine("Values: {0}, {1}", val1, val2);
Console.WriteLine("Refs: {0}, {1}", ref1.Value, ref2.Value);
}
}
显示了这种区别。运行该程序,可见下列输出:Values: 0, 123
Refs: 123, 123
给局部变量 val1 赋值不会影响局部变量 val2,这是因为两个局部变量都是值类型(int 类型),每个局部变量都保存着各自的数据。相反,赋值 ref2.Value = 123; 则会影响到 ref2,因为 ref1 和 ref2 所引用的其实是同一个对象。
应对代码行Console.WriteLine("Values: {0}, {1}", val1, val2);
Console.WriteLine("Refs: {0}, {1}", ref1.Value, ref2.Value);
做进一步解释,因为方法 Console.WriteLine 的某些字符串格式化行为较复杂,它所需的参数数目是可变的。第一个参数是字符串,它可能包含类似 {0......
C# 语言规范--1.1 开始(2006-09-03 18:26:00)
摘要:经典性“hello, world”程序可以写为:using System;
class Hello
{
static void Main() {
Console.WriteLine("hello, world");
}
}
C# 程序的源代码通常存储在一个或多个以 .cs 为文件扩展名的文本文件(如 hello.cs)中。可以通过 Visual Studio .NET 所提供的命令行编译器,使用以下命令行指令来编译此程序:csc hello.cs
它产生一个名为 hello.exe 的应用程序。当此应用程序运行时,它产生的输出是:hello, world
仔细观察此程序可以发现:
“using System;”指令引用一个名为 System 的命名空间,它由 Microsoft .NET Framework 类库定义。此命名空间包含 Main 方法中引用的 Console 类。命名空间提供了一种分层方法来组织一个或多个程序中的各种元素。用“using”指令指定一个命名空间后,该命名空间中的所有成员均可直接被引用。所以,在“hello, world”程序中,可直接使用 Console.WriteLine(而不必使用 System.Console.WriteLine)。
Main 方法是 Hello 类的成员。它具有 static 修饰符,因此 Main 方法是相对于类 Hello 本身而不是相对于此类的实例。
应用程序的入口点(即当程序开始运行时首先被调用的方法)总是名为 Main 的静态方法。
“hello, world”输出依靠类库实现。C# 语言本身不提供类库,它使用公共的类库(Visual Basic .NET 和 Visual C++ .NET 也使用它)。
对 C 和 C++ 开发人员而言,值得注意的是一些“没有”出现在“hello, world”程序中的东西。
该程序中的 Main 方法不是全局的。C# 不支持全局级别的方法和变量;这类元素总是包含在类型声明(如类声明和结构声明)中。
该程序没有使用“::”运算符和“->”运算符。在 C# 中,“::”根本不是运算符,而“->”运算符仅在一小部分程序中使用,即那些涉及不安全代码的程序。分隔符“.”在复合名称中使用,如......
C# 程序员参考--OLE DB 教程(2006-09-03 18:26:00)
摘要:OLE DB 是用于访问数据的基于 COM 的应用程序编程接口 (API)。OLE DB 支持访问以 OLE DB 提供程序可以使用的任何格式(数据库、电子表格、文本文件等)存储的数据。每个 OLE DB 提供程序从某一特定类型的数据源(例如 SQL Server 数据库、Microsoft Access 数据库或 Microsoft Excel 电子表格)公开数据。
本教程说明如何从 C# 应用程序中使用 Microsoft Access 数据库。
教程
本教程说明如何从 C# 中使用 Microsoft Access 数据库。它显示如何创建数据集并从数据库向该数据集添加表。本示例程序中使用的 BugTypes.mdb 数据库是 Microsoft Access 2000 .MDB 文件。
示例
本程序访问 BugTypes.mdb 数据库,创建一个数据集并向其中添加表,然后显示表、列和行的数目。它还显示每行的标题。
// OleDbSample.cs
using System;
using System.Data;
using System.Data.OleDb;
using System.Xml.Serialization;
public class MainClass {
public static void Main ()
{
// Set Access connection and select strings.
// The path to BugTypes.MDB must be changed if you build
// the sample from the command line:
#i......
C# 程序员参考--不安全代码教程(2006-09-03 18:25:00)
摘要:该教程说明如何在 C# 中使用不安全代码(使用指针的代码)。
教程
在 C# 中很少需要使用指针,但仍有一些需要使用的情况。例如,在下列情况中使用允许采用指针的不安全上下文是正确的:
处理磁盘上的现有结构
涉及内部包含指针的结构的高级 COM 或平台调用方案
性能关键代码
不鼓励在其他情况下使用不安全上下文。具体地说,不应该使用不安全上下文尝试在 C# 中编写 C 代码。
警告 使用不安全上下文编写的代码无法被验证为安全的,因此只有在代码完全受信任时才会执行该代码。换句话说,不可以在不受信任的环境中执行不安全代码。例如,不能从 Internet 上直接运行不安全代码。
该教程包括下列示例:
示例 1 使用指针复制一个字节数组。
示例 2 显示如何调用 Windows ReadFile 函数。
示例 3 显示如何打印可执行文件的 Win32 版本。
示例 1
以下示例使用指针将一个字节数组从 src 复制到 dst。用 /unsafe 选项编译此示例。
// fastcopy.cs
// compile with: /unsafe
using System;
class Test
{
// The unsafe keyword allows pointers to be used within
// the following method:
static unsafe void Copy(byte[] src, int srcIndex,
byte[] dst, int dstIndex, int count)
{
if (src == null || srcIndex < 0 ||
......
C# 程序员参考--线程处理教程(2006-09-03 18:25:00)
摘要:线程处理的优点是可以创建使用多个执行线程的应用程序。例如,某一进程可以具有管理与用户交互的用户界面线程,以及在用户界面线程等待用户输入时执行其他任务的辅助线程。
该教程说明各种线程活动:
创建和执行线程
线程同步
线程间交互
使用线程池
使用 mutex 对象保护共享资源
教程
该教程包含下列示例:
示例 1:创建线程、启动线程和线程间交互
示例 2:同步两个线程:制造者和使用者
示例 3:使用线程池
示例 4:使用 Mutex 对象
示例 1:创建线程、启动线程和线程间交互
本示例说明如何创建和启动线程,并显示了同时在同一进程内运行的两个线程间的交互。请注意,不必停止或释放线程。这由 .NET Framework 公共语言运行库自动完成。
程序从创建 Alpha 类型的对象 (oAlpha) 和引用 Alpha 类的 Beta 方法的线程 (oThread) 开始。然后启动该线程。线程的 IsAlive 属性允许程序等待,直到线程被初始化(被创建、被分配等)为止。主线程通过 Thread 访问,而 Sleep 方法通知线程放弃其时间片并在一定毫秒数期间停止执行。然后 oThread 被停止和联接。联接一个线程将使主线程等待它死亡或等待它在指定的时间后过期。最后,程序尝试重新启动 oThread,但由于线程无法在停止(中止)后重新启动而告失败。有关临时停止执行的信息,请参见挂起线程执行。// StopJoin.cs
using System;
using System.Threading;
public class Alpha
{
// This method that will be called when the thread is started
public void Beta()
{
while (true)
{
Console.WriteLine("Alpha.Beta is running in its own thread.");
}
}
};
public class Simple
{
public static int Main()
{
C......
C# 程序员参考--安全性教程(2006-09-03 18:23:00)
摘要:本教程讨论了 .NET Framework 安全性并显示了在 C# 修改安全权限的两种方式:命令性安全和声明性安全。
教程
大多数应用程序和组件开发人员不需完成任何特别的工作就可使用 .NET Framework 安全系统并从它所提供的安全保护中受益。
但“安全库”是一个例外,它要求了解更多深入的知识并对安全系统加以特殊考虑。这些代码表明了安全托管代码与非限制代码之间的界限,后者如本机代码(这超出了 .NET Framework 安全基础结构可以强制的范围)。这些库通常必须受到高度信任才可以工作,它们是托管代码中编程错误会潜在地暴露安全隐患的一个位置。代码访问安全性无法消除人为错误的可能性,但相对于使用几个安全库的大量应用程序代码而言,需要严格审查的代码量将大大减少。
示例
该教程包括下列示例:
示例 1:强制式安全性
示例 2:声明式安全性
示例 3:禁止安全性
安全性
.NET Framework 安全性通过在托管代码上强制实施安全限制来防止其他代码误用或破坏您的代码和数据。当 .NET Framework 应用程序请求权限时,由管理员建立的安全策略将授予权限或拒绝运行代码。信任是基于有关代码的证据(如数字签名、代码来自何处等)的。一旦授予权限,安全性就会实施控制这些代码可以做什么(或如果未授予权限,则控制代码不能做什么)的权限。
权限
.NET Framework 安全性只有当代码具有使用受保护资源的“权限”时才允许它使用这些资源。为了表示此情形,.NET Framework 使用了“权限”的概念,它表示代码访问受保护资源的权力。代码请求所需的权限,然后由 .NET Framework 应用的安全策略确定实际授予代码哪些权限。
.NET Framework 提供了代码访问权限类,其中每个类都封装了访问某一特定资源的能力。使用这些权限向 .NET Framework 指示需要允许代码做什么以及必须授权代码的调用方做什么。策略还使用这些对象确定要向代码授予哪些权限。
策略
安全策略的强制性保证了 .NET Framework 托管代码的安全。每个加载的程序集都受到安全策略的约束,安全策略基于信任授予代码权限,而信任又是基于有关代码的证据的。有关管理安全策略的信息,请参见“阅读材料列表”中的 .NET Framework 文......
C# 程序员参考--属性教程(2006-09-03 18:22:00)
摘要:本教程展示如何创建自定义属性类,如何在代码中使用它们,以及如何通过反射查询它们。
教程
属性提供功能强大的方法以将声明信息与 C# 代码(类型、方法、属性等)相关联。与程序实体关联后,属性可在运行时查询,并可以以任意多种方式使用。
属性的用法示例包括:
将帮助文档与程序实体关联(通过 Help 属性)。
将值编辑器关联到 GUI 框架中的特定类型(通过 ValueEditor 属性)。
除一个完整的示例外,本教程还包括以下主题:
声明属性类
第一件需要做的事情是声明属性。
使用属性类
创建属性后,随即将属性与特定的程序元素关联。
通过反射访问属性
属性与程序元素关联后,即可使用反射查询属性存在及其值。
声明属性类
在 C# 中声明属性很简单:它采取从 System.Attribute 继承的类声明的形式,并已用 AttributeUsage 属性标记,如下所示:using System;
[AttributeUsage(AttributeTargets.All)]
public class HelpAttribute : System.Attribute
{
public readonly string Url;
public string Topic // Topic is a named parameter
{
get
{
return topic;
}
set
{
topic = value;
}
}
public HelpAttribute(string url) // url is a positional parameter
{
this.Url = url;
}
private string topic;
}
代码讨论
属性 AttributeUsage 指定该属性可以应用于的语言元素。
属性类是从 System.Attribute 派生的公共类,至少有一个公共构造函数。
属性类有两种类型的参数:
“定位参数”......
C# 程序员参考--COM Interop 第二部分:C# 服务器教程(2006-09-03 18:21:00)
摘要:COM Interop 允许 COM 开发人员像访问其他 COM 对象一样轻松访问托管代码。本教程说明如何将 C# 服务器与 C++ COM 客户端一起使用。它还解释了下列活动:
如何创建 C# 服务器
如何创建 COM 客户端
该教程还简要说明了在托管和非托管组件之间自动应用的封送处理。
COM Interop 第一部分:C# 客户端教程显示使用 C# 与 COM 对象交互操作的基础知识,这是该教程的前提。有关两个教程的概述,请参见 COM Interop 教程。
教程
该教程说明下列创建 C# 服务器的活动:
如何使用接口和类上的 Guid 属性将其作为 COM 对象公开以及如何为 Guid 属性生成全局唯一标识符 (GUID)。
如何使用 RegAsm 注册供 COM 客户端使用的 .NET Framework 程序以及从 .NET Framework 程序创建类型库(.tlb 文件)。
该教程还说明下列创建 COM 客户端的活动:
如何导出托管服务器以及如何使用它们创建 COM 对象。
如何将由 RegAsm 生成的 .tlb 文件导入到 COM 客户端,以及如何使用 CoCreateInstance 创建 .NET Framework coclass 的实例。
注意 若要为导出到 COM 客户端的接口和 coclass 创建 GUID,请使用 Guidgen.exe 工具,此工具是作为 Visual Studio 的一部分交付的。Guidgen 使您可以选择 GUID 的表示格式,这样您就不必重新键入它。有关 Guidgen 的更多信息,请参见知识库文章 Q168318“XADM: Guidgen.exe Available Only for Intel Platforms”。知识库文章可以在 MSDN Library 中以及 Web 站点 http://support.microsoft.com 上找到。
示例
本示例由两个文件组成:
C# 文件 CSharpServer.cs,它创建 CSharpServer.dll 文件。.dll 用于创建 CSharpServer.tlb 文件。
C++ 文件 COMClient.cpp,它创建可执行客户端 CO......
C# 程序员参考--COM Interop 第一部分:C# 客户端教程(2006-09-03 18:20:00)
摘要:COM Interop 提供对现有 COM 组件的访问,而不需要修改原始组件。若要将 COM 代码合并到托管应用程序,请通过使用 COM Interop 实用工具 (TlbImp.exe) 导入相关的 COM 类型。一经导入,COM 类型就可以使用。
此外,COM Interop 还使 COM 开发人员能够像访问其他 COM 对象一样轻松访问托管对象。同样,COM Interop 提供了一个专用实用工具 (RegAsm.exe),此工具将托管类型导出到类型库中,并将托管组件注册为传统 COM 组件。
在运行时,公共语言运行库根据需要在 COM 对象和托管对象之间封送数据。
该教程显示如何使用 C# 与 COM 对象交互操作。
COM Interop 第二部分:C# 服务器教程讲述如何将 C# 服务器与 C++ COM 客户端一起使用。有关两个教程的概述,请参见 COM Interop 教程。
教程
C# 使用 .NET Framework 功能执行 COM Interop。C# 支持:
创建 COM 对象。
确定 COM 接口是否由对象实现。
调用 COM 接口上的方法。
实现可由 COM 客户端调用的对象和接口。
.NET Framework 使用 COM Interop 处理引用计数问题,因此不必调用或实现 AddRef 和 Release。
本教程阐述以下主题:
创建 COM 类包装
声明 COM coclass
创建 COM 对象
声明 COM 接口
使用转换而不是 QueryInterface
综述
创建 COM 类包装
要使 C# 代码引用 COM 对象和接口,需要在 C# 内部版本中包含 COM 接口的 .NET Framework 定义。完成此操作的最简单方法是使用 TlbImp.exe(类型库导入程序),它是一个包括在 .NET Framework SDK 中的命令行工具。TlbImp 将 COM 类型库转换为 .NET Framework 元数据,从而有效地创建一个可以从任何托管语言调用的托管包装。用 TlbImp 创建的 .NET Framework 元数据可以通过 /R 编译器选项包括在 C# 内部版本中。如果使用 Visual Studio 开发环境,则只需添加对 CO......
C# 程序员参考--平台调用教程(2006-09-03 18:19:00)
摘要:平台调用服务 (PInvoke) 允许托管代码调用在 DLL 中实现的非托管函数。
本教程说明使用什么方法才能从 C# 调用非托管 DLL 函数。该教程所讨论的属性允许您调用这些函数并使数据类型得到正确封送。
教程
C# 代码有以下两种可以直接调用非托管代码的方法:
直接调用从 DLL 导出的函数。
调用 COM 对象上的接口方法(有关更多信息,请参见 COM Interop 第一部分:C# 客户端教程)。
对于这两种技术,都必须向 C# 编译器提供非托管函数的声明,并且还可能需要向 C# 编译器提供如何封送与非托管代码之间传递的参数和返回值的说明。
该教程由下列主题组成:
直接从 C# 调用 DLL 导出
默认封送处理和为非托管方法的参数指定自定义封送处理
为用户定义的结构指定自定义封送处理
注册回调方法
该教程包括下列示例:
示例 1 使用 DllImport
示例 2 重写默认封送处理
示例 3 指定自定义封送处理
直接从 C# 调用 DLL 导出
若要声明一个方法使其具有来自 DLL 导出的实现,请执行下列操作:
使用 C# 关键字 static 和 extern 声明方法。
将 DllImport 属性附加到该方法。DllImport 属性允许您指定包含该方法的 DLL 的名称。通常的做法是用与导出的方法相同的名称命名 C# 方法,但也可以对 C# 方法使用不同的名称。
还可以为方法的参数和返回值指定自定义封送处理信息,这将重写 .NET Framework 的默认封送处理。
示例 1
本示例显示如何使用 DllImport 属性通过调用 msvcrt.dll 中的 puts 输出消息。// PInvokeTest.cs
using System;
using System.Runtime.InteropServices;
class PlatformInvokeTest
{
[DllImport("msvcrt.dll")]
public static extern int puts(string c);
[DllImport("msvcrt.dll")]
internal static extern int _......