类型 字节 描述
byte 1 unsigned byte
sbyte 1 signed byte
short 2 signed short
ushort 2 unsigned short
int 4 signed integer
uint 4 unsigned integer
long 8 signed long
ulong 8 unsigned long
float 4 floating point number
double 8 double precision number
decimal 8 fixed precision number
string - Unicode string
char - Unicode char
bool true, false boolean
注意:C# 的类型范围和 C++ 不同。例如:long 在 C++ 中是 4 字节而在 C# 中是 8 字节。bool 和 string 类型均和 C++ 不同。bool 仅接受真、假而非任意整数。
用户定义类型文件包含:
1. 类 (class)
2. 结构(struct)
3. 接口(interface)
以下类型继承时均分配内存:
1. 值类型
2. 参考类型
值类型
值类型是在堆栈中分配的数据类型。它们包括了:
• 除字符串,所有基本和内建类型
• 结构
• 枚举类型
引用类型
引用类型在堆(heap)中分配内存且当其不再使用时,将自动进行垃圾清理。和 C++ 要求用户显示创建 delete 运算符不一样,它们使用新运算符创建,且没有 delete 运算符。在 C# 中它们自动由垃圾回收系统回收。
除了内存分配的不同外,类和结构就和 C++ 中的情况一样。类的对象在堆中分配,并使用 new 关键字创建。而结构是在栈(stack)中进行分配。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++ 来说,前面例子中 Date 类的属性就是 day、month 和 year,而你添加了 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;
}
}
这里是你 get 和 set 属性的方法:
复制内容到剪贴板
代码:
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);
}
}
修饰符
你必须知道 C++ 中常用的 public、private 和 protected 修饰符。我将在这里讨论一些 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 关键字。
复制内容到剪贴板
代码:
sealed class CanNotbeTheParent
{
int a = 5;
}
unsafe
你可以使用 unsafe 修饰符在 C# 中定义一个不安全上下文。在不安全上下文中,你可以插入不安全代码,如 C++ 的指针等。参见以下代码:
复制内容到剪贴板
代码:
public unsafe MyFunction( int * pInt, double* pDouble)
{
int* pAnotherInt = new int;
*pAnotherInt = 10;
pInt = pAnotherInt;
...
*pDouble = 8.9;
}
接口
如果你有 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)
{
... // 做要做的事
}
// 类自身的方法
public void MoveShape(int newX, int newY)
{
.....
}
1.现在在执行一条 case 语句后,程序流不能跳至下一 case 语句。之前在 C++ 中这是可以的。
例子:
复制内容到剪贴板
代码:
int var = 100;
switch (var)
{
case 100: Console.WriteLine("<Value is 100>"); // 这里没有 break
case 200: Console.WriteLine("<Value is 200>"); break;
}
C++ 的输出:
复制内容到剪贴板
代码:
<Value is 100><Value is 200>
而在 C# 中你将得到一个编译时错误:
复制内容到剪贴板
代码:
error CS0163: Control cannot fall through
from one case label ('case 100:') to another
2.然而你可以像在 C++ 中一样这么用:
复制内容到剪贴板
代码:
switch (var)
{
case 100:
case 200: Console.WriteLine("100 or 200<VALUE is 200>"); break;
}
3.你还可以用常数变量作为 case 值:
string WeekDay = Console.ReadLine();
switch (WeekDay )
{
case WeekEnd: Console.WriteLine("It's weekend!!"); break;
case WeekDay1: Console.WriteLine("It's Monday"); break;
}
委托
委托让我们可以把函数引用保存在变量中。这就像在 C++ 中使用 typedef 保存函数指针一样。
委托使用关键字 delegate 声明。看看这个例子,你就能理解什么是委托:
例子:
复制内容到剪贴板
代码:
delegate int Operation(int val1, int val2);
public int Add(int val1, int val2)
{
return val1 + val2;
}
public int Subtract (int val1, int val2)
{
return val1- val2;
}
public void Perform()
{
Operation Oper;
Console.WriteLine("Enter + or - ");
string optor = Console.ReadLine();
Console.WriteLine("Enter 2 operands");
你可以隐藏基类中的函数而在子类中定义其新版本。关键字 new 用于声明新的版本。思考下面的例子,该例是上一例子的修改版本。注意输出,我用 关键字 new 替换了 Rectangle 类中的关键字 override。
复制内容到剪贴板
代码:
class Shape
{
public virtual void Draw()
{
Console.WriteLine("Shape.Draw") ;
}
}
class Rectangle : Shape
{
public new void Draw()
{
Console.WriteLine("Rectangle.Draw");
}
}
class Square : Rectangle
{
//这里不用 override
public new void Draw()
{
Console.WriteLine("Square.Draw");
}
}
class MainClass
{
static void Main(string[] args)
{
Console.WriteLine("Using Polymorphism:");
Shape[] shp = new Shape[3];
Rectangle rect = new Rectangle();
shp[0] = new Shape();
shp[1] = rect;
shp[2] = new Square();
shp[0].Draw();
shp[1].Draw();
shp[2].Draw();
Console.WriteLine("Using without Polymorphism:");
rect.Draw();
Square sqr = new Square();
sqr.Draw();
}
}
Output:
Using Polymorphism
Shape.Draw
Shape.Draw
Shape.Draw
Using without Polymorphism:
Rectangle.Draw
Square.Draw
多态性认为 Rectangle 类的 Draw 方法是和 Shape 类的 Draw 方法不同的另一个方法,而不是认为是其多态实现。所以为了防止父类和子类间的命名冲突,我们只有使用 new 修饰符。