绪论
C#是这样的一种语言,具备C++的特色,象Java同样的编程风格, 而且象Basic同样的快速开发模型。若是你已经知道了C++,本文会在不到一个小时的时间内让你迅速掌握C#的语法。熟悉Java的话会更好,由于Java的程序结构、打包(Packages)和垃圾收集的概念有助于你更快的了解C#。所以在讨论C#的构造时,我会假定你了解C++。
本文会讨论C#语言的构造与特色,同时会采起简洁的和你能理解的方式使用些代码示例,咱们会尽可能让你能稍微看看这些代码就能理解这些概念。
注意:本文不是为C#高手(C# gurus)所写. 这是针对在C#学习上仍是初学者的文章。
下面是将要讨论的C#问题的目录:
程序结构 命名空间 数据类型 变量
运算符和表达式 枚举
语句(Statements )
类(Classes)和结构(Structs) 修饰符(Modifiers) 属性(Properties) 接口(Interfaces)
方法参数(Function Parameters) 数组(Arrays) 索引器(Indexers) 装箱及拆箱操做 委托(Delegates) 继承和多态
下面的内容将不会在被讨论之列:
C++与C#谁更通用
诸如垃圾回收、线程以及文件处理等概念 数据的类型转换 异常处理 .NET库
------------------- 程序结构 编程
------------------ 数组
这一点象C++,C#是一种对大小写字母敏感的语言,分号“;”是语句间的分隔符。与C++不一样的是,C#当中声明代码文件(头文件)与实现代码文件(cpp文件)不是独立存在的,全部代码(类声明和类实现)都位于一个扩展名为cs的文件内。安全
让咱们瞧瞧C#当中的Hello world程序是怎样的。函数
using System; 学习
namespace MyNameSpace ui
{ this
class HelloWorld spa
{ 线程
static void Main(string[] args) 指针
{
Console.WriteLine ("Hello World");
}
}
}
在C#当中的每样东西都被封装到一个类中,C#的类又被封装到一个命名空间当中(就象一个文件夹中的文件)。相似于C++,main方法是你的程序的入口点。C++的main函数调用名称是"main",而C#的main函数是以大写字母M起点的名称是"Main"。
没有必要把分号分隔符放在类语句块或者结构定义语句块后。这在C++当中被要求,但在C#当中却不是。
-------------------
命名空间
-----------------
每个类都被包装进一个命名空间。命名空间的概念与C++的彻底相同,但在C#当中使用命名空间的频率较C++还高。你可使用点限定符(dot qulifier)访问一个类。在上面的hello world程序当中MyNameSpace就是一个命名空间。
如今思考这样的一个问题,你想从某些别的类的命名空间当中来访问HelloWorld这个类如何操做。
这有一个例子:
using System;
namespace AnotherNameSpace
{
class AnotherClass
{
public void Func()
{
Console.WriteLine ("Hello World");
}
}
}
如今,从你的HelloWorld类里你能象这样去访问上面的这个AnotherNameSpace的命名空间:
using System;
using AnotherNameSpace; // you will add this using statement
namespace MyNameSpace
{
class HelloWorld
{
static void Main(string[] args)
{
AnotherClass obj = new AnotherClass();
obj.Func();
}
}
}
在.NET库当中,System是位于顶层的命名空间,别的命名空间都存在这个命名空间之下。默认状态下,存在一个全局的命名空间,所以一个在命名空间外定义的类将直接在这个全局命名空间之下;所以,你能在没有任何点限定符的状况下访问这个类。
你也能够象下面这样定义嵌套的命名空间。
Using C++当中的"#include"指示被C#的"using"关键字取代,它后面跟着一个命名空间的名字。正如上面的"using System"。"System"是别的全部被封装的命名空间和类中最底层的命名空间。全部对象的基类都是System命名空间内的Object类派生的。
------------------
变量
-------------------
除如下区别外,C#当中的变量几乎与C++同:
与C++不一样,C#变量被访问以前必须被初始化;不然编译时会报错。所以,访问一个未初始化变量是不可能的事。
C#中你不会访问到一个不肯定的指针。(译者注:严格提及来C#已经把指针概念异化,限制更严格。因此有些资料上会说C#取消了指针概念) 一个超出数组边界的表达式是不可访问的。 C#中没有全局的的变量或全局函数,全局方式的操做是经过静态函数和静态变量来实现的。
------------------- 数据类型
-------------------
全部C#数据类型都派生自基类Object。这里有两类数据类型:
基本型/内置型 用户自定义型
下面一个C#内置类型列表:
类型 字节数 解释
byte 1 无符号字节型 sbyte 1 有符号字节型 short 2 有符号短字节型 ushort 2 无符号短字节型 int 4 有符号整型 uint 4 无符号整型 long 8 有符号长整型 ulong 8 无符号长整型 float 4 浮点数 double 8 双精度数 decimal 8 固定精度数 string Unicode 字串型 char Unicode 字符型 bool 真假 布尔型
注意:C#当中的类型范围与C++有所不一样;例如,C++的long型是4个字节,而在C#当中是8个字节。一样地,bool型和string型都不一样于C++。bool型只接受true和false两种值。不接受任何整数类型。
用户定义类型包括:
类类型(class) 结构类型(struct) 接口类型(interface)
根据数据类型的内存分配形式的不一样又把它们分红了两种类型:
值类型(value Types)
引用类型(Reference Types)
值类型:
值类型数据在栈中分配。他们包括:全部基本或内置类型(不包括string类型)、结构类型、枚举类型(enum type)
引用类型:
引用类型在堆中分配,当它们再也不被使用时将被垃圾收集。它们使用new运算符来建立,对这些类型而言,不存在C++当中的delete操做符,根本不一样于C++会显式使用delete这个运算符去释放建立的这个类型。C#中,经过垃圾收集器,这些类型会自动被收集处理。
引用类型包括:类类型、接口类型、象数组这样的集合类型类型、字串类型。
枚举类型与C++当中的概念很是类似。它们都经过一个enum关键字来定义。
示例:
enum Weekdays {
Saturday, Sunday, Monday, Tuesday, Wednesday, Thursday, Friday }
类类型与结构类型的比较
除了在内存分配形式上外,类与结构的概念彻底与C++相同。类的对象被分配在堆中,而且经过new来建立,结构也是被new建立但却被分配在栈当中。C#当中,结构型适于快速访问和拥有少许成员的数据类型。若是涉及量较多,你应该建立一个类来实现他。
(译者注:这与堆和栈内存分配结构的特色有关。简而言之,栈是一种顺序分配的内存;堆是不必定是连续的内存空间。具体内容须要你们参阅相关资料)
示例:
struct Date {
int day; int month; int year; }
class Date {
int day; int month;
int year;
string weekday;
string monthName;
public int GetDay()
{
return day;
}
public int GetMonth()
{
return month;
}
public int GetYear()
{
return year;
}
public void SetDay(int Day)
{
day = Day
}
public void SetMonth(int Month)
{
month = Month;
}
public void SetYear(int Year)
{
year = Year;
}
public bool IsLeapYear()
{
return (year/4 == 0);
}
public void SetDate (int day, int month, int year)
{
}
...
}
-------------------
属性
-------------------
若是你熟悉
C++
面象对象的方式,你就必定有一个属性的概念。在上面示例当中,以
C++
的观点来看,
Data
类的属性就是
day
、
month
和
year
。用
C#
方式,你能够把它们写成
Get
和
Set
方法。
C#
提供了一个更方便、简单、直接的方式来访问属性。
所以上面的类能够被写成:
using System;
class Date
{
public int Day{
get {
return day;
}
set {
day = value;
}
}
int day;
public int Month{
get {
return month;
}
set {
month = value;
}
}
int month;
public int Year{
get {
return year;
}
set {
year = value;
}
}
int year;
public bool IsLeapYear(int year)
{
return year%4== 0 ? true: false;
}
public void SetDate (int day, int month, int year)
{
this.day = day;
this.month = month;
this.year = year;
}
}
你可在这里获得并设置这些属性:
class User
{
public static void Main()
{
Date date = new Date();
date.Day = 27;
date.Month = 6;
date.Year = 2003;
Console.WriteLine("Date: {0}/{1}/{2}", date.Day,
date.Month,
date.Year);
}
}
-------------------
修饰符
-------------------
你必须已经知道
public
、
private
、
protected
这些常在
C++
当中使用的修饰符。这里我会讨
论一些
C#
引入的新的修饰符。
readonly
(只读)
readonly
修饰符仅在类的数据成员中使用。正如这名字所提示的,
readonly
数据成员仅能
只读,
它们只能在构造函数或是直接初始化操做下赋值一次。
readonly
与
const
数据成员不
同,
const
要求你在声明中初始化,这是直接进行的。看下面的示例代码:
class MyClass
{
const int constInt = 100; //
直接初始化
readonly int myInt = 5; //
直接初始化
readonly int myInt2; //
译者注:仅作声明,未作初始化
public MyClass()
{
myInt2 = 8; //
间接的
}
public Func()
{
myInt = 7; //
非法操做(译者注:不得赋值两次)
Console.WriteLine(myInt2.ToString());
}
}
sealed
(密封)
密封类不容许任何类继承,它没有派生类。所以,你能够对你不想被继承的类使用
sealed
关键字。
sealed class CanNotbeTheParent
{
int a = 5;
}
unsafe
(不安全)
你可以使用
unsafe
修饰符来定义一个不安全的上下文。
在不安全的上下文里,
你能写些如
C++
指针这样的不安全的代码。看下面的示例代码:
public unsafe MyFunction( int * pInt, double* pDouble)
{
int* pAnotherInt = new int;
*pAnotherInt = 10;
pInt = pAnotherInt;
...
*pDouble = 8.9;
}
-------------------
interface
(接口)
-------------------
若是你有
COM
方面的概念,
你会马上明白我要谈论的内容。
一个接口就是一个抽象的基类,
这个基类仅仅包含功能描述,而这些功能的实现则由子类来完成。
C#
中你要用
interface
关
键字来定义象接口这样的类。
.NET
就是基于这样的接口上的。
C#
中你不支持
C++
所容许的
类多继承(译者注:
即一个派生类能够从两个或两个以上的父类中派生)。
可是多继承方式
能够经过接口得到。也就是说你的一个子类能够从多个接口中派生实现。
using System;
interface myDrawing
{
int originx
{
get;
set;
}
int originy
{
get;
set;
}
void Draw(object shape);
}
class Shape: myDrawing
{
int OriX;
int OriY;
public int originx
{
get{
return OriX;
}
set{
OriX = value;
}
}
public int originy
{
get{
return OriY;
}
set{
OriY = value;
}
}
public void Draw(object shape)
{
... // do something
}
/ class's own method
public void MoveShape(int newX, int newY)
{
.....
}
}
-------------------
Arrays
(数组)
-------------------
C#
中的数组比
C++
的表现更好。数组被分配在堆中,所以是引用类型。你不可能访问超出
一个数组边界的元素。所以,
C#
会防止这样类型的
bug
。一些辅助方式能够循环依次访问
数组元素的功能也被提供了,
foreach
就是这样的一个语句。
与
C++
相比,
C#
在数组语法上
的特色以下:
方括号被置于数据类型以后而不是在变量名以后。
建立数组元素要使用
new
操做符。
C#
支持一维、多维以及交错数组(数组中的数组)。
示例:
int[] array = new int[10]; //
整型一维数组
for (int i = 0; i < array.Length; i++)
array = i;
int[,] array2 = new int[5,10]; //
整型二维数组
array2[1,2] = 5;
int[,,] array3 = new int[5,10,5]; //
整型的三维数组
array3[0,2,4] = 9;
int[][] arrayOfarray = = new int[2]; //
整型交错数组(数组中的数组)
arrayOfarray[0] = new int[4];
arrayOfarray[0] = new int[] {1,2,15};
索引器
-------------------
索引器被用于写一个访问集合元素的方法,集合使用
"[]"
这样的直接方式,相似于数组。你
所要作的就是列出访问实例或元素的索引清单。
类的属性带的是输入参数,
而索引器带的是
元素的索引表,除此而外,他们两者的语法相同。
示例:
注意:
CollectionBase
是一个制做集合的库类。
List
是一个
protected
型的
CollectionBase
成员,储存着集合清单列表。
class Shapes: CollectionBase
{
public void add(Shape shp)
{
List.Add(shp);
}
//indexer
public Shape this[int index]
{
get {
return (Shape) List[index];
}
set {
List[index] = value
}
}
}
------------------
装箱和拆箱操做(
Boxing/Unboxing
)
-------------------
C#
的装箱思想是全新的。上面提到过全部的数据类型,不论内置或用户自定义,全都从命
名空间
System
的一个基类
object
派生出来。所以把基本的或者原始类型转换成
object
类
型被称作装箱,反之,这种方式的逆操做被称为拆箱。
示例:
class Test
{
static void Main()
{
int myInt = 12;
object obj = myInt //
装箱
int myInt2 = (int) obj; //
拆箱
}
}
示例展现了装箱和拆箱操做。一个整型值转换成
object
类型,而后又转换回整型。当一个
值类型的变量须要转换成引用类型时,一个
object
的箱子会被分配容纳这个值的空间,这
个值会被复制进这个箱子。拆箱与此相反,一个
object
箱子中的数据被转换成它的原始值
类型时,这个值将被从箱中复制到适当的存储位置。