本文主要是介绍MSDN C#教程整理,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
数组教程:
声明数组时,方括号 ([]) 必须跟在类型后面,而不是标识符后面。在 C# 中,将方括号放在标识符后是不合法的语法。
int[] table; // not int table[];
另一细节是,数组的大小不是其类型的一部分,而在 C 语言中它却是数组类型的一部分。这使您可以声明一个数组并向它分配 int 对象的任意数组,而不管数组长度如何。
int[] numbers; // declare numbers as an int array of any size
numbers = new int[10]; // numbers is a 10-element array
numbers = new int[20]; // now it's a 20-element array
一维数组:
int[] numbers;
多维数组:
string[,] names;
数组的数组(交错的):
byte[][] scores;
声明数组(如上所示)并不实际创建它们。在 C# 中,数组是对象(本教程稍后讨论),必须进行实例化。下面的示例展示如何创建数组:
一维数组:
int[] numbers = new int[5];
多维数组:
string[,] names = new string[5,4];
数组的数组(交错的):
byte[][] scores = new byte[5][];
for (int x = 0; x < scores.Length; x++)
{
scores[x] = new byte[4];
}
可以用 foreach 语句对数组进行遍历。
属性教程:
· public string Name
· {
· get
· {
· return myName;
· }
· set
· {
· myName = value;
· }
· }
Visual C# 语言概念
从命令行生成
通过在命令行上键入 C# 编译器可执行文件的名称 (csc.exe),可以在命令行调用 C# 编译器。如果希望从计算机上的任何子目录调用 csc.exe,可能需要调整路径。
本主题提供有关以下内容的详细信息:
· 运行 VCVARS32.BAT
· C# 编译器和 C++ 编译器输出之间的差异
· 命令行语法规则
· 命令行示例
运行 VCVARS32.BAT
vcvars32.bat 设置适当的环境变量以启用命令行编译。
运行 VCVARS32.BAT
1. 在命令提示处,更改为安装的 /bin 子目录。
2. 通过键入 VCVARS32,运行 VCVARS32.bat。
警告 VCVARS32.bat 因计算机的不同而变化。不要用其他计算机上的 VCVARS32.bat 替换丢失或损坏的 VCVARS32.bat 文件。重新运行安装程序以替换丢失的文件。
有关 vcvars32.bat 的更多信息,请参见下面的知识库文章:
· Q248802 : Vcvars32.bat Generates Out of Environment Message
如果 Visual Studio 当前版本安装在已经拥有 Visual Studio 早期版本的计算机上,则不应在同一命令窗口中运行来自不同版本的 vcvars32.bat。
C# 编译器和 C++ 编译器输出之间的差异
作为调用 C# 编译器的结果,没有创建任何对象 (.obj) 文件;直接创建输出文件。因此,C# 编译器不需要链接器。
命令行语法规则
当解释操作系统命令行上给出的参数时,C# 编译器代码使用下面的规则:
· 参数用空白分隔,空白可以是一个空格或制表符。
· ^ 字符 (^) 未被识别为转义符或者分隔符。该字符在被传递给程序中的 argv 数组前,完全由操作系统的命令行分析器进行处理。
· 无论其中有无空白,包含在双引号 ("string") 中的字符串均被解释为单个参数。带引号的字符串可以嵌入在参数内。
· 前面有反斜杠的双引号 (/") 被解释为原义双引号字符 (")。
· 反斜杠按其原义解释,除非它们紧位于双引号之前。
· 如果偶数个反斜杠后跟双引号,则每对反斜杠中的一个反斜杠放置在 argv 数组中,并且双引号被解释为字符串分隔符。
· 如果奇数个反斜杠后跟双引号,则每对反斜杠中的一个反斜杠放置在 argv 数组中,双引号由其余的反斜杠“转义”,使原义双引号 (") 被放置在 argv 数组中。
命令行示例
· 编译 File.cs 以产生 File.exe:
csc File.cs
· 编译 File.cs 以产生 File.dll:
csc /target:library File.cs
· 编译 File.cs 并创建 My.exe:
csc /out:My.exe File.cs
· 通过使用优化和定义 DEBUG 符号,编译当前目录中所有的 C# 文件。输出为 File2.exe:
csc /define:DEBUG /optimize /out:File2.exe *.cs
· 编译当前目录中所有的 C# 文件,以产生 File2.dll 的调试版本。不显示任何徽标和警告:
csc /target:library /out:File2.dll /warn:0 /nologo /debug *.cs
· 将当前目录中所有的 C# 文件编译为 Something.xyz(一个 DLL):
csc /target:library /out:Something.xyz *.cs
库教程
先生成dll模块,然后在主程序中用using命令调用,要注意的是dll文件必须在同一文件夹内。
版本控制教程
在 C# 中,默认情况下方法不是虚拟的。若要使方法成为虚拟方法,必须在基类的方法声明中使用 virtual 修饰符。然后,派生类可以使用 override 关键字重写基虚拟方法,或使用 new 关键字隐藏基类中的虚拟方法。如果 override 关键字和 new 关键字均未指定,编译器将发出警告,并且派生类中的方法将隐藏基类中的方法。
需要注意:new关键字和override关键字得到的是截然相反的结果,默认是new方法。
集合类教程
foreach 语句是循环访问数组元素的方便方法。如果集合类已实现 System.Collections.IEnumerator 和 System.Collections.IEnumerable 接口,它还可以枚举该集合的元素。
在 C# 中,集合类并非必须严格从 IEnumerable 和 IEnumerator 继承才能与 foreach 兼容;只要类有所需的 GetEnumerator、MoveNext、Reset 和 Current 成员,便可以与 foreach 一起使用。省略接口的好处为,使您可以将 Current 的返回类型定义得比 object 更明确,从而提供了类型安全。
下面的代码示例阐释如何编写可与 foreach 一起使用的集合类。该类是字符串标记化拆分器,类似于 C 运行时库函数 strtok。
// tokens.cs
using System;
// The System.Collections namespace is made available:
using System.Collections;
// Declare the Tokens class:
public class Tokens : IEnumerable
{
private string[] elements;
Tokens(string source, char[] delimiters)
{
// Parse the string into tokens:
elements = source.Split(delimiters);
}
// IEnumerable Interface Implementation:
// Declaration of the GetEnumerator() method
// required by IEnumerable
public IEnumerator GetEnumerator()
{
return new TokenEnumerator(this);
}
// Inner class implements IEnumerator interface:
private class TokenEnumerator : IEnumerator
{
private int position = -1;
private Tokens t;
public TokenEnumerator(Tokens t)
{
this.t = t;
}
// Declare the MoveNext method required by IEnumerator:
public bool MoveNext()
{
if (position < t.elements.Length - 1)
{
position++;
return true;
}
else
{
return false;
}
}
// Declare the Reset method required by IEnumerator:
public void Reset()
{
position = -1;
}
// Declare the Current property required by IEnumerator:
public object Current
{
get
{
return t.elements[position];
}
}
}
// Test Tokens, TokenEnumerator
static void Main()
{
// Testing Tokens by breaking the string into tokens:
Tokens f = new Tokens("This is a well-done program.",
new char[] {' ','-'});
foreach (string item in f)
{
Console.WriteLine(item);
}
}
}
结构教程
结构可能看似类,但存在一些重要差异,应引起注意。首先,类为引用类型,而结构为值类型。使用结构,您可以创建行为类似内置类型的对象,同时享有它们的好处。
堆还是堆栈?
在类上调用“新建”(New) 运算符时,它将在堆上进行分配。但是,当实例化结构时,将在堆栈上创建结构。这样将产生性能增益。而且,您不会像对待类那样处理对结构实例的引用。您将直接对结构实例进行操作。鉴于此原因,向方法传递结构时,结构将通过值传递,而不是作为引用传递。
结构可以声明构造函数,但它们必须带参数。声明结构的默认(无参数)构造函数是错误的。结构成员不能有初始值设定项。总是提供默认构造函数以将结构成员初始化为它们的默认值。
使用 New 运算符创建结构对象时,将创建该结构对象,并且调用适当的构造函数。与类不同的是,结构的实例化可以不使用 New 运算符。如果不使用“新建”(new),那么在初始化所有字段之前,字段将保持未赋值状态,且对象不可用。
对于结构,不像类那样存在继承。一个结构不能从另一个结构或类继承,而且不能作为一个类的基。但是,结构从基类对象继承。结构可实现接口,而且实现方式与类实现接口的方式完全相同。
结构使用简单,并且有时证明很有用。但要牢记:结构在堆栈中创建,并且您不是处理对结构的引用,而是直接处理结构。每当需要一种将经常使用的类型,而且大多数情况下该类型只是一些数据时,结构可能是最佳选择。
索引器教程
定义“索引器”使您可以创建作为“虚拟数组”的类。该类的实例可以使用 [] 数组访问运算符进行访问。在 C# 中定义索引器类似于在 C++ 中定义运算符 [],但前者灵活得多。对于封装类似数组的功能或类似集合的功能的类,使用索引器使该类的用户可以使用数组语法访问该类。
示例
本示例中,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 should be the last thing done
// when you are finished.
public void Close()
{
stream.Close();
stream = null;
}
// Indexer to provide read/write access to the file.
public byte this[long index] // long is a 64-bit integer
{
// Read one byte at offset index and return it.
get
{
byte[] buffer = new byte[1];
stream.Seek(index, SeekOrigin.Begin);
stream.Read(buffer, 0, 1);
return buffer[0];
}
// Write one byte at offset index and return it.
set
{
byte[] buffer = new byte[1] {value};
stream.Seek(index, SeekOrigin.Begin);
stream.Write(buffer, 0, 1);
}
}
// Get the total length of the file.
public long Length
{
get
{
return stream.Seek(0, SeekOrigin.End);
}
}
}
// Demonstrate the FileByteArray class.
// Reverses the bytes in a file.
public class Reverse
{
public static void Main(String[] args)
{
// Check for arguments.
if (args.Length == 0)
{
Console.WriteLine("indexer <filename>");
return;
}
FileByteArray file = new FileByteArray(args[0]);
long len = file.Length;
// Swap bytes in the file to reverse it.
for (long i = 0; i < len / 2; ++i)
{
byte t;
// Note that indexing the "file" variable invokes the
// indexer on the FileByteStream class, which reads
// and writes the bytes in the file.
t = file[i];
file[i] = file[len - i - 1];
file[len - i - 1] = t;
}
file.Close();
}
}
输入:indexer.txt
若要测试程序,可使用具有以下内容的文本文件(该文件在“索引器”示例中称为 Test.txt)。
public class Hello1
{
public static void Main()
{
System.Console.WriteLine("Hello, World!");
}
}
若要反转该文件的字节,请编译程序,然后使用下面的命令行:
indexer indexer.txt
若要显示反转的文件,请输入命令:
Type indexer.txt
示例输出
}
}
;)"!dlroW ,olleH"(eniLetirW.elosnoC.metsyS
{
)(niaM diov citats cilbup
{
1olleH ssalc cilbup
用户定义的转换教程
C# 允许程序员在类或结构上声明转换,以便可以使类或结构与其他类或结构或者基本类型相互进行转换。转换的定义方法类似于运算符,并根据它们所转换到的类型命名。
在 C# 中,可以将转换声明为 implicit(需要时自动转换)或 explicit(需要调用转换)。所有转换都必须为 static,并且必须采用在其上定义转换的类型,或返回该类型。
示例 2
本示例定义 RomanNumeral 和 BinaryNumeral 两个结构,并演示二者之间的转换。
// structconversion.cs
using System;
struct RomanNumeral
{
public RomanNumeral(int value)
{
this.value = value;
}
static public implicit operator RomanNumeral(int value)
{
return new RomanNumeral(value);
}
static public implicit operator RomanNumeral(BinaryNumeral binary)
{
return new RomanNumeral((int)binary);
}
static public explicit operator int(RomanNumeral roman)
{
return roman.value;
}
static public implicit operator string(RomanNumeral roman)
{
return("Conversion not yet implemented");
}
private int value;
}
struct BinaryNumeral
{
public BinaryNumeral(int value)
{
this.value = value;
}
static public implicit operator BinaryNumeral(int value)
{
return new BinaryNumeral(value);
}
static public implicit operator string(BinaryNumeral binary)
{
return("Conversion not yet implemented");
}
static public explicit operator int(BinaryNumeral binary)
{
return(binary.value);
}
private int value;
}
class Test
{
static public void Main()
{
RomanNumeral roman;
roman = 10;
BinaryNumeral binary;
// Perform a conversion from a RomanNumeral to a
// BinaryNumeral:
binary = (BinaryNumeral)(int)roman;
// Performs a conversion from a BinaryNumeral to a RomanNumeral.
// No cast is required:
roman = binary;
Console.WriteLine((int)binary);
Console.WriteLine(binary);
}
}
输出
10
Conversion not yet implemented
运算符重载教程
示例 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 Main()
{
Complex num1 = new Complex(2,3);
Complex num2 = new Complex(3,4);
// Add two Complex objects (num1 and num2) through the
// overloaded plus operator:
Complex sum = num1 + num2;
// Print the numbers and the sum using the overriden ToString method:
Console.WriteLine("First complex number: {0}",num1);
Console.WriteLine("Second complex number: {0}",num2);
Console.WriteLine("The sum of the two numbers: {0}",sum);
}
}
输出
First complex number: 2 + 3i
Second complex number: 3 + 4i
The sum of the two numbers: 5 + 7i
委托教程
· 声明委托 以下语句:
public delegate void ProcessBookDelegate(Book book);
声明一个新的委托类型。每个委托类型都描述参数的数目和类型,以及它可以封装的方法的返回值类型。每当需要一组新的参数类型或新的返回值类型时,都必须声明一个新的委托类型。
· 实例化委托 声明了委托类型后,必须创建委托对象并使之与特定方法关联。与所有其他对象类似,新的委托对象用 new 表达式创建。但是当创建委托时,传递给 new 表达式的参数很特殊:它的编写类似于方法调用,但没有方法的参数。
下列语句:
bookDB.ProcessPaperbackBooks(new ProcessBookDelegate(PrintTitle));
创建与静态方法 Test.PrintTitle 关联的新的委托对象。下列语句:
bookDB.ProcessPaperbackBooks(new
ProcessBookDelegate(totaller.AddBookToTotal));
创建与对象 totaller 上的非静态方法 AddBookToTotal 关联的新的委托对象。在两个例子中,新的委托对象都立即传递给 ProcessPaperbackBooks 方法。
请注意一旦创建了委托,它所关联到的方法便永不改变:委托对象不可改变。
· 调用委托 创建委托对象后,通常将委托对象传递给将调用该委托的其他代码。通过委托对象的名称(后面跟着要传递给委托的参数,括在括号内)调用委托对象。下面是委托调用的示例:
processBook(b);
委托的+-例程
// compose.cs
using System;
delegate void MyDelegate(string s);
class MyClass
{
public static void Hello(string s)
{
Console.WriteLine(" Hello, {0}!", s);
}
public static void Goodbye(string s)
{
Console.WriteLine(" Goodbye, {0}!", s);
}
public static void Main()
{
MyDelegate a, b, c, d;
// Create the delegate object a that references
// the method Hello:
a = new MyDelegate(Hello);
// Create the delegate object b that references
// the method Goodbye:
b = new MyDelegate(Goodbye);
// The two delegates, a and b, are composed to form c:
c = a + b;
// Remove a from the composed delegate, leaving d,
// which calls only the method Goodbye:
d = c - a;
Console.WriteLine("Invoking delegate a:");
a("A");
Console.WriteLine("Invoking delegate b:");
b("B");
Console.WriteLine("Invoking delegate c:");
c("C");
Console.WriteLine("Invoking delegate d:");
d("D");
}
}
输出
Invoking delegate a:
Hello, A!
Invoking delegate b:
Goodbye, B!
Invoking delegate c:
Hello, C!
Goodbye, C!
Invoking delegate d:
Goodbye, D!
事件教程
· 声明事件 若要在类内声明事件,首先必须声明该事件的委托类型(如果尚未声明的话)。
public delegate void ChangedEventHandler(object sender, EventArgs e);
委托类型定义传递给处理该事件的方法的一组参数。多个事件可共享相同的委托类型,因此仅当尚未声明任何合适的委托类型时才需要执行该步骤。
接下来,声明事件本身。
public event ChangedEventHandler Changed;
声明事件的方法与声明委托类型的字段类似,只是关键字 event 在事件声明前面,在修饰符后面。事件通常被声明为公共事件,但允许任意可访问修饰符。
· 调用事件 类声明了事件以后,可以就像处理所指示的委托类型的字段那样处理该事件。如果没有任何客户将委托与该事件挂钩,该字段将为空;否则该字段引用应在调用该事件时调用的委托。因此,调用事件时通常先检查是否为空,然后再调用事件。
· if (Changed != null)
Changed(this, e);
调用事件只能从声明该事件的类内进行。
· 与事件挂钩 从声明事件的类外看,事件像个字段,但对该字段的访问是非常受限制的。只可进行如下操作:
· 在该字段上撰写新的委托。
· 从字段(可能是复合字段)移除委托。
使用 += 和 -= 运算符完成此操作。为开始接收事件调用,客户代码先创建事件类型的委托,该委托引用应从事件调用的方法。然后它使用 += 将该委托写到事件可能连接到的其他任何委托上。
// Add "ListChanged" to the Changed event on "List":
List.Changed += new ChangedEventHandler(ListChanged);
当客户代码完成接收事件调用后,它将使用运算符 -= 从事件移除其委托。
// Detach the event and delete the list:
List.Changed -= new ChangedEventHandler(ListChanged);
.NET Framework 指南
尽管 C# 语言允许事件使用任意委托类型,但“.NET Framework”对于应为事件使用的委托类型有一些更严格的指南。如果打算将您的组件与“.NET Framework”一起使用,您可能希望遵守这些指南。
“.NET Framework”指南指示用于事件的委托类型应采用两个参数:指示事件源的“对象源”参数和封装事件的其他任何相关信息的“e”参数。“e”参数的类型应从 EventArgs 类派生。对于不使用其他任何信息的事件,“.NET Framework”已定义了一个适当的委托类型:EventHandler。
显式接口实现教程
实现接口的类可以显式实现该接口的成员。当显式实现某成员时,不能通过类实例访问该成员,而只能通过该接口的实例访问该成员.
示例 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) myBox;
// Print out the dimensions of the box:
/* The following commented lines would produce compilation
errors because they try to access an explicitly implemented
interface member from a class instance: */
//System.Console.WriteLine("Length: {0}", myBox.Length());
//System.Console.WriteLine("Width: {0}", myBox.Width());
/* Print out the dimensions of the box by calling the methods
from an instance of the interface: */
System.Console.WriteLine("Length: {0}", myDimensions.Length());
System.Console.WriteLine("Width: {0}", myDimensions.Width());
}
}
输出
Length: 30
Width: 20
示例 2
显式接口实现还允许程序员继承共享相同成员名的两个接口,并为每个接口成员提供一个单独的实现。本示例同时以公制单位和英制单位显示框的尺寸。Box 类继承 IEnglishDimensions 和 IMetricDimensions 两个接口,它们表示不同的度量衡系统。两个接口有相同的成员名 Length 和 Width。
// explicit2.cs
// Declare the English units interface:
interface IEnglishDimensions
{
float Length();
float Width();
}
// Declare the metric units interface:
interface IMetricDimensions
{
float Length();
float Width();
}
// Declare the "Box" class that implements the two interfaces:
// IEnglishDimensions and IMetricDimensions:
class Box : IEnglishDimensions, IMetricDimensions
{
float lengthInches;
float widthInches;
public Box(float length, float width)
{
lengthInches = length;
widthInches = width;
}
// Explicitly implement the members of IEnglishDimensions:
float IEnglishDimensions.Length()
{
return lengthInches;
}
float IEnglishDimensions.Width()
{
return widthInches;
}
// Explicitly implement the members of IMetricDimensions:
float IMetricDimensions.Length()
{
return lengthInches * 2.54f;
}
float IMetricDimensions.Width()
{
return widthInches * 2.54f;
}
public static void Main()
{
// Declare a class instance "myBox":
Box myBox = new Box(30.0f, 20.0f);
// Declare an instance of the English units interface:
IEnglishDimensions eDimensions = (IEnglishDimensions) myBox;
// Declare an instance of the metric units interface:
IMetricDimensions mDimensions = (IMetricDimensions) myBox;
// Print dimensions in English units:
System.Console.WriteLine("Length(in): {0}", eDimensions.Length());
System.Console.WriteLine("Width (in): {0}", eDimensions.Width());
// Print dimensions in metric units:
System.Console.WriteLine("Length(cm): {0}", mDimensions.Length());
System.Console.WriteLine("Width (cm): {0}", mDimensions.Width());
}
}
条件方法教程
文件 #2:使用条件方法
下面的客户程序使用文件 #1 中定义的 Trace 类来执行一些简单跟踪。
// TraceTest.cs
// compile with: /reference:CondMethod.dll
// arguments: A B C
using System;
using TraceFunctions;
public class TraceClient
{
public static void Main(string[] args)
{
Trace.Message("Main Starting");
if (args.Length == 0)
{
Console.WriteLine("No arguments have been passed");
}
else
{
for( int i=0; i < args.Length; i++)
{
Console.WriteLine("Arg[{0}] is [{1}]",i,args[i]);
}
}
Trace.Message("Main Ending");
}
}
线程处理教程
· 创建和执行线程
· 线程同步
· 线程间交互
· 使用线程池
· 使用 mutex 对象保护共享资源
这篇关于MSDN C#教程整理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!