c#关键字
关键字是对编译器有特殊意义的预定义的保留标识符。它们不能在程序中用作普通标识符,除非在它们前面加上@前缀。
第一部分
一.访问关键字:base,this
base:访问基类的成员。
用于从派生类中访问基类的成员,
1.调用基类上已经被重写的方法。
2.指定创建派生类实例时应调用的基类构造函数。
**对基类的访问只能在 派生类的构造函数 实例的方法 实例的属性访问器 中。
属性访问器:get,set函数。
注意:!!!!!!!!!
不能在静态方法中使用base关键字。
例:
在子类的方法中写 base.GetInfo();调用基类的方法。
基类中的构造函数重载了,Mybase()和Mybase(int i);
在子类的构造函数中public MyDerived():base(int i)
public MyDerived(int i):base()
this:引用当前对象。
用于引用为其调用方法的当前实例。
静态成员函数没有this指针。
可以用于从 构造函数,实例方法,实例访问器 中访问成员。
this的一般用途:
1.限定被相似的名子隐藏的成员
public void A(int a, int b )
{
this.a=a;
this.b=b;
}
2.将对象作为参数传递到函数中
public void ShowInstance()
{
print(this);
console.writeline("lalalalllalalala");
}
3.声明索引器
public int this[int param]
{
get{ return array[param]; }
set{ array[param]=value; }
}
注意!!!!!!静态方法,静态属性访问器或字段声明中不能用this。
二.转换关键字:explicit, implicit, operator
1、explicit:
用于声明用户定义的 显式类型转换运算符。
例:
class MyType
{
public static explicit operator MyType(int i)
{
//从int显式转换成MyType类型的代码!!!
}
}
显式类型转换符必须通过类型转换调用。需要在转换失败时抛出异常。
if(转换失败的条件)
throw new ArgumentException();
int i;
MyType x = (MyType)i;
注意!!!!!!!如果转换可能导致信息丢失,则使用explicit关键字。
2、implicit:
用于声明用户定义的 隐式类型转换运算符。
例:
class MyType
{
public static implicit operator int(MyType i)
{
//从MyType隐式转换成Mint类型的代码!!!
}
}
MyType i;
int x = i;
注意!!!!!!!!!!!由于隐式转换在程序员未指定的情况下发生,所以必须防止出现不良的后果。只有在一定不会出现异常和信息丢失时才可以使用implicit,否则使用expicit。
3、operator:
用于声明用户在类或结构中自定义的运算符。有四种形式:
public static 结果类型 operator unary-operator (参数类型 参数名)
public static implict operator 目标类型 (输入类型 参数名)
public static explict operator 目标类型 (输入类型 参数名)
//implict中,目标类型一般是封闭类型,例如:int, double, byte等。
//explict中,目标类型一般是自定义类型,例如:MyType等。
三.文字关键字:null,false,true
1、 null:
表示不引用任何对象的空引用的值。null是引用类型的默认值。
2、 true:
true运算符:用户自定义的类型可以重载true运算符,用来表示是否满足条件,若满足则返回bool值的true,否则返回false。
注意!!!!!!!若在自定义类型中定义了true运算符,则必须定义false运算符。
true文字值:表示bool的真。
3、false:
false运算符:用户自定义的类型可以重载false运算符,用来表示是否满足条件,若不满足则返回bool值的true,否则返回false。
注意!!!!!!!若在自定义类型中定义了false运算符,则必须定义true运算符。
false文字值:表示bool的假。
true和false运算符可以用在任何条件判断中。
四.方法参数关键字:params,ref,out
1、params:用于指定在参数数目可变处,采用参数的方法参数。只能有一个params,并且在他后面不能再有参数。
方法参数:如果在为方法声明参数时未使用 ref 或 out,则该参数可以具有关联的值。可以在方法中更改该值,但当控制传递回调用过程时,不会保留更改的值
using System;
public class MyClass
{
public static void UseParams(params int[] list)
{
for (int i = 0 ; i < list.Length; i++)
{
Console.WriteLine(list[i]);
}
Console.WriteLine();
}
public static void UseParams2(params object[] list)
{
for (int i = 0 ; i < list.Length; i++)
{
Console.WriteLine(list[i]);
}
Console.WriteLine();
}
static void Main()
{
UseParams(1, 2, 3);
UseParams2(1, 'a', "test");
// An array of objects can also be passed, as long as
// the array type matches the method being called.
int[] myarray = new int[3] {10,11,12};
UseParams(myarray);
}
}
输出
1
2
3
1
a
test
10
11
12
//把1,2,3三个参数当成一个数组处理,在最后输出Console.WriteLine();
2、ref:使方法可以引用传递到该方法的参数。当程序跳转到调用方法处的时候,在方法中对参数所做的任何改动都将传递给参数。类似于传地址。
注意!!!!!必须将参数作为ref参数 显示 的传递到方法。参数必须显示的初始化!属性不是变量不能作为ref参数传递。
例子:
using System;
using System.Collections.Generic;
using System.Text;
namespace 真的是关键字
{
class Program
{
public static void TestRef(ref string i)
{
i = "change once!";
}
public static void TestNoRef(string i)
{
i = "change twice!";
}
static void Main(string[] args)
{
string i = "begining!";
Console.WriteLine(i);
TestRef(ref i);
Console.WriteLine(i);
TestNoRef(i);
Console.WriteLine(i);
Console.ReadLine();
}
}
}
输出:
beginning!
Change once!
Change once!
3、out:使方法可以引用传递到该方法的同一个变量。当程序跳转到方法调用处时,在方法中对变量所做的任何改动都将传递给该变量。
注意!!!!!当希望方法返回多个值时,声明out非常有用。
一个方法可以有多个out参数。
必须将参数作为out参数显示的传递到方法。
不必初始化作为out参数的变量。
属性不是变量不能作为out变量。
注意!!!!!ref参数必须显示初始化,而out参数不用。
例子:
using System;
using System.Collections.Generic;
using System.Text;
namespace 真的是关键字
{
class Program
{
public static int TestOut(out string i)
{
i = "change once!";
return -1;
}
static void Main(string[] args)
{
string i = "begining!";
Console.WriteLine(i);
Console.WriteLine(TestOut(out i));
Console.WriteLine(i);
Console.ReadLine();
}
}
}
5.修饰关键字
1.访问关键字
不嵌套在其他类型中的顶级类型只能有public和internal可访问性,默认是internal。
嵌套类型的可访问性取决于它的可访问域,而且不能超出包含它类型的可访问域。
2.可访问域
1.可访问域:用于指定程序段中可以引用该成员的位置。如果是嵌套类型,那么它的可访问域由成员的访问级别和直接包含该成员的类型的可访问域共同决定。
using System;
using System.Collections.Generic;
using System.Text;
namespace 真的是关键字
{
public class T1
{
public static int publicInt;
internal static int internalInt;
private static int privateInt = 0; // CS0414
public class M1
{
public static int publicInt;
internal static int internalInt;
private static int privateInt = 0; // CS0414
}
private class M2
{
public static int publicInt = 0;
internal static int internalInt = 0;
private static int privateInt = 0; // CS0414
}
}
class MainClass
{
static void Main()
{
// Access is unlimited:
T1.publicInt = 1;
// Accessible only in current assembly:
T1.internalInt = 2;
// Error: inaccessible outside T1:
// T1.myPrivateInt = 3;
// Access is unlimited:
T1.M1.publicInt = 1;
// Accessible only in current assembly:
T1.M1.internalInt = 2;
// Error: inaccessible outside M1:
// T1.M1.myPrivateInt = 3;
// Error: inaccessible outside T1:
// T1.M2.myPublicInt = 1;
// Error: inaccessible outside T1:
// T1.M2.myInternalInt = 2;
// Error: inaccessible outside M2:
// T1.M2.myPrivateInt = 3;
}
}
}
3.对使用可访问性级别的限制
1~~~~基类的可访问性必须不小于派生类。
2、派生类的可访问性必须不大于基类。
3、成员的可访问性至少是包含它的类。
例子:
Class BaseClass{};
Public class MyClass: BaseClass{};
这是错误的!!!!!!!!!!!!!!!!
对使用声明的而访问型级别限制
4.访问修饰关键字
1、internal:是类型和类型成员的访问修饰符,只有在同一个程序集中才可以访问。
通俗的说就是:如果用internal修饰,那么只能在定义它的.cs文件中访问它。在别的文件中访问就会出错。
5.其它修饰关键字
1、abstract:可用来修饰 类,方法和属性。
(1) 在类的声明中使用abstract,表示这个类只能作为其他类的基类,即抽象类。
抽象类的特点:
a.抽象类不能实例化。
b.抽象类可以包含抽象方法和抽象访问器。
c.不能用sealed修饰抽象类,否则,该类不能被继承。
d.从抽象类派生的非抽象类必须包含继承来的所有抽象方法和抽象访问器的实实现。
(2) 在方法和属性中使用abstract,表示此方法或属性 不包含实现。即抽象方法和抽象属性。
抽象方法的特点:
A. 抽象方法是隐式的virtual方法。
B. 只允许在抽象类中定义抽象方法。
C. 抽象方法不提供实现,所以没有方法体。 格式如下:没有{}!!!!
Public abstract void MyMethod();
D. 实现由重写方法提供,他是非抽象的。
E. 抽象方法中使用virtual, static, override关键字是错误的。
F. 静态属性上不能使用abstract关键字。
G. 在派生类中,通过使用override 可以重写抽象的继承属性。
H. 抽象类必须为所有接口成员提供实现,或将其映射到抽象方法上去。
// abstract_keyword.cs
// Abstract Classes
using System;
abstract class BaseClass // Abstract class
{
protected int _x = 100;
protected int _y = 150;
public abstract void AbstractMethod(); //Abstract method
public abstract int X { get; }
//abstract property
public abstract int Y { get; }
}
class DerivedClass : BaseClass
{
public override void AbstractMethod()
{
_x++;
_y++;
}
}
public override int X // overriding property
{
get
{
return _x + 10;
}
public override int Y // overriding property
{
get
{
return _y + 10;
}
}
static void Main()
{
DerivedClass o = new DerivedClass();
o.AbstractMethod();
Console.WriteLine("x = {0}, y = {1}", o.X, o.Y);
}
}
输出
x = 111, y = 161
2.const:用来指定字段或局部变量的之不能被修改。
Public const int a=1,b=2;
3.event:用于指定一个事件。
指定当代码中的某些事件发生时调用的委托。此委托可以有一个或多个相关联的方法。
创建事件的步骤:
1. 创建或标示一个委托。先有委托后定义事件。
2. 创建一个类,其中包含:
A. 委托创建的事件。
B. 调用此事件的方法。
3. 定义将方法连接到事件的类。
4. 使用事件:创建包含事件声明类的对象。
4.extern:表示方法在外部实现。
注意!!!!!不能将extern和abstract一起使用。
格式举例:public static extern int MyMethod (int x); 没有{}
5.override:用于修改方法和属性,通过 override 声明重写的方法称为重写基方法。重写的基方法必须与 override 方法具有相同的签名。
重写基方法:有重写声明的方法。
注意!!!!!不能重写非虚方法或静态方法。
不能使用以下关键字修饰重写方法:new,static,virtual,abstract
重写的属性与重写的方法的要求是一样的。
重写的方法中可以调用基类的原来的virtual方法。
namespace 真的是关键字
{
public class Square
{
public double x;
public Square(double x)
{
this.x = x;
}
public virtual double Area()
{
return (x*x);
}
}
class Cube : Square
{
public Cube(double x):base(x)
{
}
public override double Area()
{
return (6*base.Area());//调用base即基类的方法。
}
}
class MainClass
{
static void Main()
{
double x = 5.2;
Square s = new Square(x);
Square c = new Cube(x);
Console.WriteLine("Area of Square is{0:F2}",s.Area());
Console.WriteLine("Area of Cube is {0:F2}", c.Area());
Console.ReadLine();
}
}
}
6.readonly:只可以使用在字段上,被readonly修饰的字段的赋值只能作为 声明的一部分或者在构造函数中。
1.在声明中初始化:public readonly double a=1.1;
2.在构造函数中。
readonly 关键字与 const 关键字不同:const 字段只能在该字段的声明中初始化。readonly段可以在声明或构造函数中初始化。因此,根据所使用的构造函数,readonly 字段可能具有不同的值。另外,const 字段为编译时常数,而 readonly 字段可用于运行时常数。
输出
p1: x=11, y=21, z=32
p2: x=55, y=25, z=24
7.sealed:由sealed修饰的类是不能够被继承的。不允许用abstract修饰密封类。
密封类:由sealed关键字修饰的类。
例子:
Public sealed class MyClass
{
Public Int a;
}
MyClass是不能被继承的。
8.static:用于声明属于类型本身而不是属于特定对象的静态成员。
- 注意!!!!!:常数或者类型声明隐式地是静态成员。
- 不能通过实例引用静态成员。然而,可以通过类型名称引用它
9.unsafe:表示不安全的上下文。任何涉及指针的操作都要求有不安全的上下文。Unsafe用作可调用成员的生命修饰符。
例子:不安全范围从参数列表一直到函数结尾,所以可以在参数列表中使用指针。
Static unsafe void FastCopy(byte* bt, int count)
{ //函数体,其中可以使用指针! }
若要编译非托管代码,必须指定unsafe编译器选项.
10.virtual:用于修饰可以在子类中重写的方法或属性.此种方法或属性称为 虚拟成员.虚拟成员可以在派生类中用override重写.
注意!!!!!:
不能重写非虚方法,不能将其与static, abstract,和override起使用.
不能在静态属性或方法上使用virtual.
在运行时,为虚方法检查对象中是否有重写的方法,如果有,则调用重写的方法,否则调用基类的方法.
10.volatile:
volatile 关键字表示字段可能被多个并发执行线程修改。声明为 volatile 的字段不受编译器优化(假定由单个线程访问)的限制。这样可以确保该字段在任何时间呈现的都是最新的值。
volatile 修饰符通常用于由多个线程访问而不使用 lock 语句语句对访问进行序列化的字段。volatile 关键字可应用于以下类型:
- 引用类型。
- 指针类型(在不安全的上下文中)。
- 整型,如 sbyte、byte、short、ushort、int、uint、char、float 和 bool。
- 具有整数基类型的枚举类型。
- 已知为引用类型的泛型类型参数。
- IntPtr 和 UIntPtr。
所涉及的类型必须是类或结构的字段。不能将局部变量声明为 volatile
例子:
class MainClass
{
public volatile int i;//定义在main函数之外,是全局变量.
Test(int _i)
{
i = _i;
}
static void Main()
{
// ...
}
}
6.命名空间关键字
一.namespace
1.Namespace :用于声明一个空间。其中可以包含:另一个命名空间,class,interface,struct,enum,delegate.
2.每一个文件中都有默认的全局命名空间,命名空间的默认访问权限是公共的,且不可以改变。
3.可以在多个声明中定义一个命名空间。
namespace MyCompany.Proj1
{
class MyClass
{
}
}
namespace MyCompany.Proj1
{
class MyClass1
{
}
}
二.Using
Using关键字的主要用途:1.using 指令:用于为命名空间创建别名或导入其他命名空间中定义的类型。
2.using 语句:定义一个范围,在范围的末尾将处理对象。
1.using指令:1.创建命名空间的别名。以便易于将标示符限定到命名空间或类。
2.允许在命名空间中使用(其他命名空间中的)类型。
using 别名 = 希望被起别名的命名空间或类;
例子:
using System; //using 指令
using AliasToMyClass = NameSpace1.MyClass; // 为类起别名
namespace NameSpace1
{
public class MyClass
{
public override string ToString()
{
return "You are in NameSpace1.MyClass";
}
}
}
namespace NameSpace2
{
class MyClass
{
}
}
namespace NameSpace3
{
// Using directive:
using NameSpace1;//using指令,可以使用其中定义的类型而不
//名命名空间
// Using directive:
using NameSpace2;
class MainClass
{
static void Main()
{
AliasToMyClass somevar = new AliasToMyClass();
Console.WriteLine(somevar);
}
}
}
2.using 语句
1.定义一个范围,在范围的末尾处理对象。
注意!!!!!:在using语句中创建一个实例,可确保在using语句结束时,释放该对象。但是,被实例化的对象(他所属的类)中必须实现
System.IDisposable接口中的disposable方法,就是利用该方法释放对象。
例子:
using System;
using System.Collections.Generic;
using System.Text;
namespace 真的是关键字
{
class C : IDisposable //继承IDisposable接口
{
public void UseLimitedResource()
{
Console.WriteLine("Using limited resource...");
}
void IDisposable.Dispose()//实现Dispose()方法
{
Console.WriteLine("Disposing limited resource.");
}
}
class Program
{
static void Main()
{
using (C c = new C())
{
c.UseLimitedResource();
}
Console.WriteLine("Now outside using statement.");
Console.ReadLine();
}
}
}
输出:
Using limited resource...
Disposing limited resource.
Now outside using statement.
语法:using (C c = new C())
{
c.UseLimitedResource();
}
在CLR决定让GC回收某些有限资源之前释放它们,有时很有用,尤其对于象文件句柄,网络连接的有限资源。
7.运算符关键字
一.as
作用:用于执行可兼容类型之间的转换。
语法格式:expression as type
例子:string s = objArray[i] as string;
1.As运算符类似于类型转换,不同的是,当转换失败时,类型转换将引发异常,而,as运算符将返回空即NULL。
2.其中的expression表达式只被计算一次。
例子:
using System;
class Class1
{
}
class Class2
{
}
class MainClass
{
static void Main()
{
object[] objArray = new object[6];
objArray[0] = new Class1();
objArray[1] = new Class2();
objArray[2] = "hello";
objArray[3] = 123;
objArray[4] = 123.4;
objArray[5] = null;
for (int i = 0; i < objArray.Length; ++i)
{
string s = objArray[i] as string;
Console.Write("{0}:", i);
if (s != null)
{
Console.WriteLine("'" + s + "'");
}
else
{
Console.WriteLine("not a string");
}
}
}
}
输出:
0:not a string
1:not a string
2:'hello'
3:not a string
4:not a string
5:not a string
二.Is关键字
1.Is:用于检查对象在运行时的类型是否与给定类型兼容。
2.语法格式:expression is type
例子:
3.当expression为非空并且可以被转化为type类型时,整个表达式返回true,否则返回false。
4.is运算符不能被重载。
例子:
using System;
class Class1
{
}
class Class2
{
}
class IsTest
{
static void Test(object o)
{
Class1 a;
Class2 b;
if (o is Class1)
{
Console.WriteLine("o is Class1");
a = (Class1)o;
// Do something with "a."
}
else if (o is Class2)
{
Console.WriteLine("o is Class2");
b = (Class2)o;
// Do something with "b."
}
else
{
Console.WriteLine("o is neither Class1 nor Class2.");
}
}
static void Main()
{
Class1 c1 = new Class1();
Class2 c2 = new Class2();
Test(c1);
Test(c2);
Test("a string");
}
}
输出:
o is Class1
o is Class2
o is neither Class1 nor Class2.
3.new关键字
New关键字在C#中可以用作:1.运算符
2.修饰符
New运算符:用于在堆上创建对象和调用构造函数。
New修饰符:用于隐藏基类成员的继承成员。
一.New运算符:用于在堆上创建对象和调用构造函数。
二.堆是在运行是根据需要分配的,而栈在编译时分配的。
例子:
Class1 o = new Class1();
int i = new int();为值类型调用默认构造函数,i=0;
注意!!!!!:为结构声明默认构造函数是错误的。但是可以声明参数化构造函数。
值类型对象是在栈(stack)上创建的,而引用类型是在堆(heap)上创建的。
不能重载new关键字
对值类型如果不进行人为初始化,编译器会对他进行默认初始化。对引用类型不进行初始化则为空(NULL)。
例子:
using System;
using System.Collections.Generic;
using System.Text;
namespace 真的是关键字
{
struct SampleStruct
{
public int x;
public int y;
public SampleStruct(int x, int y)
{
this.x = x;
this.y = y;
}
}
class SampleClass
{
public string name;
public int id;
public SampleClass()
{
}
public SampleClass(int id, string name)
{
this.id = id;
this.name = name;
}
}
class MainClass
{
static void Main()
{
//结构类型默认初始化
SampleStruct Location1 = new SampleStruct();
SampleClass Employee1 = new SampleClass();
// Display values:
Console.WriteLine("Default values:");
Console.WriteLine(" Struct members: {0}, {1}",
Location1.x, Location1.y);
Console.WriteLine(" Class members: {0}, {1}",
Employee1.name, Employee1.id);
// Create objects using parameterized constructors:
SampleStruct Location2 = new SampleStruct(10, 20);
SampleClass Employee2 = new SampleClass(1234, "John Martin Smith");
// Display values:
Console.WriteLine("Assigned values:");
Console.WriteLine(" Struct members: {0}, {1}",
Location2.x, Location2.y);
Console.WriteLine(" Class members: {0}, {1}",
Employee2.name, Employee2.id);
Console.ReadLine();
}
}
}
三.New修饰符:用于以显式的形式隐藏从基类继承来的成员。即:告诉编译器或CLR我要有意隐藏基类的同签名的成员。隐藏继承的成员意味着该成员的派生版本将替换基类版本
四.通过继承方式实现名称隐藏:引入与基类中要隐藏的成员具有相同签名的派生类成员。
注意!!!!!在同一成员上同时使用new和override是错误的。
例子:
using System;
using System.Collections.Generic;
using System.Text;
namespace 真的是关键字
{
public class BaseC
{
public static int x = 55;
public static int y = 22;
}
public class DerivedC : BaseC
{
// Hide field 'x'
new public static int x = 100;
static void Main()
{
// Display the new value of x:
Console.WriteLine(x);
// Display the hidden value of x:
Console.WriteLine(BaseC.x);
// Display the unhidden member y:
Console.WriteLine(y);
Console.ReadLine();
}
}
}
4,sizeof关键字
1. sizeof关键字:用于获得值类型的大小,以字节为单位。
2. 语法格式:sizeof(type)
3. 注意!!!!!sizeof() 只能用于值类型,不能用于引用类型,并且只能用于unsafe模式下。Sizeof()不能被重载。
例子:
using System;
using System.Collections.Generic;
using System.Text;
namespace 真的是关键字
{
class MainClass
{
unsafe static void Main()
{
Console.WriteLine("The size of short is {0}.", sizeof(short));
Console.WriteLine("The size of int is {0}.", sizeof(int));
Console.WriteLine("The size of long is {0}.", sizeof(long));
}
}
}
五.Typeof关键字
1.typeof()关键字:用于获得某一类型的System.Type对象。
2.语法格式:typeof( type )
例子:
System.Type type = typeof(int);
4. typeof()运算符不能重载。要获得一个对象运行时的类型,可以使用.NET框架中的方法GetType().
5. 例子:
int i = 0;
System.Type type = i.GetType();
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
namespace 真的是关键字
{
public class SampleClass
{
public int sampleMember;
public void SampleMethod()
{
}
static void Main()
{
Type t = typeof(SampleClass);
// Alternatively, you could use
// SampleClass obj = new SampleClass();
// Type t = obj.GetType();
Console.WriteLine("Methods:");
MethodInfo[] methodInfo = t.GetMethods();
foreach (MethodInfo mInfo in methodInfo)
{
Console.WriteLine(mInfo.ToString());
}
Console.WriteLine("Members:");
MemberInfo[] memberInfo = t.GetMembers();
foreach (MemberInfo mInfo in memberInfo)
{
Console.WriteLine(mInfo.ToString());
}
Console.ReadLine();
}
}
}
六.True关键字
1.true运算符:用户可以自定义true()运算符,该运算符返回bool值true表示真,false表示假。
2.如果定义了true或者false中的一个,那么必须定义另一个。
3.true文字值:表示bool的真。
七.false关键字
1.false运算符:用户可以自定义false()运算符,该运算符返回bool型值true表示假,false表示真。
2.如果定义了true或者false中的一个,那么必须定义另一个。
3.false文字值:表示bool的假。
例子:
sing System;
class TestClass
{
static void Main()
{
Bool b=false;
bool a = true;
Console.WriteLine( a ? "yes" : "no" );
Console.WriteLine( b ? "yes" : "no" );
}
}
八.Stackalloc关键字
1.stackalloc:该运算符用于在堆栈上分配内存块。
2.语法格式:
type * ptr = stackalloc type [ expr ];
在堆栈上(stack)分配内存,其大小足以包含type类型的expr个元素。
3.内存地址保存在ptr指针中,此内存不受立即回收的制约,生存周期仅限定于该内存块所在方法的生存周期。没有在方法返回之前释放内存的途径
4.因为涉及指针类型,stackalloc需要不安全的上下文。
8.语句关键字
2.switch关键字
1.注意:每个语句块(无论是case还是default),必须要以(1)break结束(2)goto语句。C#不支持从一个case标签显示的贯穿到另一个case标签。只有一个例外,就是当case语句中没有代码时。
例子:
using System;
class SwitchTest
{
static void Main()
{
Console.WriteLine("Coffee sizes: 1=Small 2=Medium 3=Large");
Console.Write("Please enter your selection: ");
string s = Console.ReadLine();
int n = int.Parse(s);
int cost = 0;
switch(n)
{
case 1:
cost += 25;
break;
case 2:
cost += 25;
goto case 1;
case 3:
cost += 50;
goto case 1;
default:
Console.WriteLine("Invalid selection. Please select 1, 2, or 3.");
break;
}
if (cost != 0)
{
Console.WriteLine("Please insert {0} cents.", cost);
}
Console.WriteLine("Thank you for your business.");
}
}
3.foreach和in关键字
1.foreach语句使程序为数组和对象集合中的每一个元素重复执行一个嵌入语句组。它用于迭代通过集合以获得信息,但不应用于更改集合内容以避免产生不可预期的副作用。
2.对数组使用foreach
例子:
class ForEachTest
{
static void Main(string[] args)
{
int[] fibarray = new int[] { 0, 1, 2, 3, 5, 8, 13 };
foreach (int i in fibarray) //写出数组名即可
{
System.Console.WriteLine(i);
}
}
}
3.对集合使用foreach
注意:要想迭代通过集合,集合必须满足一定的要求。
(1) 集合类型:
必须是interface,class或struct。
必须包括有返回类型的名为GetEnumerator的实例方法。
(2) Enumerator类型必须包含:
一个名为Current的属性,它返回此类型属性访问器返回当前元素。
一个名为MoveNext()的方法,它递增项计数器并在集合存在更多项时返回true。
例子:
using System;
using System.Collections.Generic;
using System.Text;
namespace ConsoleApplication1
{
public class MyCollection
{
int[] items;
public MyCollection()
{
items = new int[5] { 1, 2, 3, 4, 5 };
}
public MyEnumerator GetEnumerator()
{
return new MyEnumerator(this);
}
/// <summary>
/// 声明枚举类
/// </summary>
public class MyEnumerator
{
int nIndex;
MyCollection collection;
public MyEnumerator(MyCollection coll)
{
collection = coll;
nIndex = -1;
}
public bool MoveNext()
{
nIndex++;
return (nIndex < collection.items.GetLength(0));
}
public int Current
{
get { return (collection.items[nIndex]); }
}
}
}
class Program
{
static void Main(string[] args)
{
MyCollection col = new MyCollection();
Console.WriteLine("Values in the collection are:");
//显示集合项
foreach(int i in col)
{
Console.WriteLine(i);
}
}
}
}
注:集合类(hashtable等)可以直接使用foreach方法。
3.跳转语句
1.break:可以终止距离它最近的封闭式循环结构或者条件语句的执行。
2.continue:可以使程序执行它所在的封闭迭代语句的下一次迭代。
3.goto语句
1.goto语句使程序代码直接转至标记语句。
2.goto语句的通常用法是:(1)使程序跳转至特定的switch—case标签
(2)用于跳出多层嵌套循环
例子:
switch (n)
{
case 1:
cost += 25;
break;
case 2:
cost += 25;
goto case 1;
case 3:
cost += 50;
goto case 1;
default:
Console.WriteLine("Invalid selection.");
break;
}
(2)例子:
using System;
public class GotoTest1
{
static void Main()
{
int x = 200, y = 4;
int count = 0;
string[,] array = new string[x, y];
// Initialize the array:
for (int i = 0; i < x; i++)
for (int j = 0; j < y; j++)
array[i, j] = (++count).ToString();
// Read input:
Console.Write("Enter the number to search for: ");
// Input a string:
string myNumber = Console.ReadLine();
// Search:
for (int i = 0; i < x; i++)
{
for (int j = 0; j < y; j++)
{
if (array[i, j].Equals(myNumber))
{
goto Found;
}
}
}
Console.WriteLine("The number {0} was not found.", myNumber);
goto Finish;
Found:
Console.WriteLine("The number {0} is found.", myNumber);
Finish:
Console.WriteLine("End of search.");
}
}
4.异常处理语句
1.不要在try语句块中对在try外部声明的变量进行初始化,因为不能保证它一定会被执行。
例子:
Int x;
Try
{
x = 1;
}
Catch{}
Console.Write(x);//////////////////错误!!!!!!!!!!!!
例子:try-catch语句,注意catch的顺序很重要,要逐步扩大exception的范围。
using System;
class MainClass
{
static void ProcessString(string s)
{
if (s == null)
{
throw new ArgumentNullException();
}
}
static void Main()
{
try
{
string s = null;
ProcessString(s);
}
// Most specific:
catch (ArgumentNullException e)
{
Console.WriteLine("{0} First exception caught.", e);
}
// Least specific:
catch (Exception e)
{
Console.WriteLine("{0} Second exception caught.", e);
}
}
}
2.finally:用于清除在try块中申请的资源,并且执行即使在发生异常时也必须执行的代码。无论什么情况,finally语句都一定会执行!!!!!!!!!
3.try-catch-finally:通常用法是在try块中抛出异常并申请资源,在catch块中捕获异常处理异常,在finally块中释放资源。
例子:
uusing System;
public class EHClass
{
static void Main()
{
try
{
Console.WriteLine("Executing the try statement.");
throw new NullReferenceException();
}
catch (NullReferenceException e)
{
Console.WriteLine("{0} Caught exception #1.", e);
}
catch
{
Console.WriteLine("Caught exception #2.");
}
finally
{
Console.WriteLine("Executing finally block.");
}
}
}
5.checked和unchecked关键字
1.checked:对整形算术运算符,和类型转换提供溢出检查。
2.unchecked:用于取消对算术运算符和类型转换的溢出检查。此时,算法溢出会被忽略,并且结果会被截断。
3.编译器默认的是checked。
public int UncheckedAdd(int a, int b)
{
return unchecked(a + b);
}
6.fixed语句
1.fixed语句可以防止变量被垃圾回收器重新定位。
2.只能在不安全的向下文中使用fixed。
3.fixed语句可以设置指向托管变量的指针,并且在fixed语句块执行期间锁定该变量。当fixed语句结束,被锁定的变量被取消锁定,仍然受GC的管理。C#规定,只有在fixed语句中才可以设置指向托管变量的指针。
5.无法修改在fixed语句中初始化的指针。
6.在不安全模式下,可以在stack(线程堆栈)上分配内存,线程堆栈不受GC管理,所以不用,fixed锁定。
例子:
using System;
class Point
{
public int x, y;
}
class FixedTest
{
// Unsafe method: takes a pointer to an int.
unsafe static void SquarePtrParam (int* p)
{
*p *= *p;
}
unsafe static void Main()
{
Point pt = new Point();
pt.x = 5;
pt.y = 6;
// Pin pt in place:
fixed (int* p = &pt.x) ////fixed语句,不要指向fixed语句之外的那些////变量
{
SquarePtrParam (p);
}
// pt now unpinned
Console.WriteLine ("{0} {1}", pt.x, pt.y);
}
}
7.lock语句
1.lock语句:用于标记临界区。方法是获取给定对象的互斥锁,在执行语句结束时,释放该锁。
2.语法格式:
Lock (Expression) statement_block;
其中:expression 是要被锁定的对象,它必须是引用类型。
通常,如果要保护实例变量(即lock用在类方法里),则expresson为this,
即用lock(this){ statement },如果要保护静态变量,则expression为typeof(class)。
注意:不要锁定public对象,否则会出错。最佳办法是锁定private对象。
例子:
using System;
using System.Threading;
class Account
{
private Object thisLock = new Object();
int balance;
Random r = new Random();
public Account(int initial)
{
balance = initial;
}
int Withdraw(int amount)
{
// This condition will never be true unless the lock statement
// is commented out:
if (balance < 0)
{
throw new Exception("Negative Balance");
}
// Comment out the next line to see the effect of leaving out
// the lock keyword:
lock(thisLock)
{
if (balance >= amount)
{
Console.WriteLine("Balance before Withdrawal : " + balance);
Console.WriteLine("Amount to Withdraw : -" + amount);
balance = balance - amount;
Console.WriteLine("Balance after Withdrawal : " + balance);
return amount;
}
else
{
return 0; // transaction rejected
}
}
}
public void DoTransactions()
{
for (int i = 0; i < 100; i++)
{
Withdraw(r.Next(1, 100));
}
}
}
class Test
{
static void Main()
{
Thread[] threads = new Thread[10];
Account acc = new Account(1000);
for (int i = 0; i < 10; i++)
{
Thread t = new Thread(new ThreadStart(acc.DoTransactions));
threads[i] = t;
}
for (int i = 0; i < 10; i++)
{
threads[i].Start();
}
}
}
九.类型关键字
C#中有三种类型:
1. 值类型
2. 引用类型
3. 指针类型
值类型:
1. 结构:A.数值类型:整型,浮点型,decimal型
B.bool
c.用户自定义的结构
结构类型:是一种值类型,用于封装一组相关变量,可以包含构造函数,常量,字段,方法,属性,索引器,运算符,事件,嵌套类型。
结构可以实现接口,但是不能实现继承,其中的成员也不能声明为protected。
2.枚举:using System;
public class EnumTest
{
enum Range :long {Max = 2147483648L, Min = 255L};
static void Main()
{
long x = (long)Range.Max;
long y = (long)Range.Min;
Console.WriteLine("Max = {0}", x);
Console.WriteLine("Min = {0}", y);
}
}
注意:
1.基于值类型的变量直接包含值。将一个值类型变量赋给另一个值类型变量时,将复制包含的值。这与引用类型变量的赋值不同,引用类型变量的赋值只复制对对象的引用,而不复制对象本身。
2.所有的值类型均隐式派生自 System.ValueType。
3.与引用类型不同,从值类型不可能派生出新的类型。但与引用类型相同的是,结构也可以实现接口。
4.与引用类型不同,值类型不可能包含 null 值。然而,可空类型功能允许将 null 赋给值类型。
例如:Nullable <int> a = null;(但是只能判断a是否等于null,不能将null作为输出,否则引发异常)或int? a = null;
4.每种值类型均有一个隐式的默认构造函数来初始化该类型的默认值。有关值类型默认值的信息。
1.bool关键字
1. bool是System.Boolean的别名。
2. 转换:不存在bool类型与其他任何类型的相互转换。
3. If()条件判断时必须是bool类型的值。例如:int x = 1; if(x){}是错误的。必须将该变量于一个值进行显示比较。
2.byte关键字
1.转换:byte x = 10; 合法
Int a = 10; byte x = a; 不合法,目标量必须占有更大的存储空间(byte是目标量),除非进行显示类型转换。
3.char关键字
4.demical关键字
1.demical类型具有更高的精度和更小的范围。适用于财务和货币计算。
2.如果希望将实数视为demical类型。则在后面加上m或M。
例如:demical d = 300.01m;
5.double关键字
1.默认情况下,等号右边的实数将会被视为double类型。但是,要想将整数视为double类型,在后面加上d或者D。
例如: double d = 3d;
6.enum
1.enum关键字用于声明枚举,enum类型是由一组称为枚举数列表的命名常量组成的特殊类型。
2.每种枚举类型均有一组基础类型,此基础类型可以是除char类型之外的任何整形。
例子: using System;
public class EnumTest
{
enum Range :long {Max = 2147483648L, Min = 255L};
//基础类型是long
static void Main()
{
long x = (long)Range.Max;
long y = (long)Range.Min;
Console.WriteLine("Max = {0}", x);
Console.WriteLine("Min = {0}", y);
}
}
3.从枚举类型到其他类型需要显示的类型转换(无论基础类型是什么!)。.
7.float关键字
1.要想使实数变成float类型,后面加上f.例如:float f = 3.5f;
8.Int关键字
9.long类型
1.要想使整数变成long类型,在后面加上l或L。例如:long L = 64L;
10.sbyte
带符号的byte类型。
11.short类型
带符号的16位整数。
12.struct关键字
1.结构类型:是一种值类型,用于封装一组相关变量,可以包含构造函数,常量,字段,方法,属性,索引器,运算符,事件,嵌套类型。
结构可以实现接口,但是不能实现继承,其中的成员也不能声明为protected。
2. struct是在stack上分配空间。
3. 结构类型对具有语意的小型结构尤为有用。
4. 声明结构的默认构造函数(就是没有参数的构造函数)是错误的。因为C#中已经提供了默认构造函数。
5. 在结构中初始化实例字段是错误的。
13.uint关键字
1.无符号32位整数。
2.在整数后面加上u,即可以把整数变成无符号的数,根据其值的大小判断是uint还是ulong。
14.ulong关键字
1.无符号64位整数。
15.ushort关键字
1.无符号16位整数。
九.装箱和取消装箱
1.装箱
1.对值类型装箱会使之变为一个对象,会在heap(垃圾回收堆)上为其分配存储空间,创建object对象,并将其值复制到对象。
2.原始值类型和装箱对象使用不同的内存,可以存储不同的值。
装箱转换
在heap上分配存储空间创建新对象,是在stack上的object引用其值。(boxed)i和(unboxed)i存储在不同内存中。
class TestBoxing
{
static void Main()
{
int i = 123;
object o = i; // implicit boxing
i = 456; // change the contents of i
System.Console.WriteLine("The value-type value = {0}", i);
System.Console.WriteLine("The object-type value = {0}", o);
}
}
2.取消装箱
进行装箱和取消装箱都会进行大量计算,降低性能。
1.取消装箱是将object对象装换成值类型。
2.取消装箱将执行下列操作:
A.检查该object对象,确保它是要转换成的值类型的一个装箱值。
B.将object对象的值复制到值类型对象中。
3.要想成功取消装箱,必须保证:(1)该object对象是某个值的引用,null不行。
(2)object对象必须是在对该值类型的值装箱时创建的。
(3)取消装箱必须是显示的。
取消装箱转换
例子:
class TestUnboxing
{
static void Main()
{
int i = 123;
object o = i; // implicit boxing
try
{
int j = (short) o; // attempt to unbox
System.Console.WriteLine("Unboxing OK.");
}
catch (System.InvalidCastException e)
{
System.Console.WriteLine("{0} Error: Incorrect
unboxing.", e.Message);
}
}
}
将short改成int就可以获得Unboxing ok.
3.引用类型
1.引用类型变量又称为对象,可以存储对实际数据的引用。
2.常用的引用类型:class,interface,delegate,object,string.
1.class
2.delegate
3.interface
1.接口的作用是定义某种合约,实现接口的类和结构必须遵守这种合约。
2.一个接口可以继承多个接口,接口本身并不向其中的成员提供实现,而是有继承该接口的类和结构实现。
3.当类继承了类和接口时,类写在前面。
4.object
1.object类基于system.object类。可以将任何类型的值赋予object类变量。
2.所有数据,无论是预定义的还是用户自定义的都继承自object类。
3.object类型是同对象进行拆装箱的类型。
5.string关键字
1.string类型是引用类型,但是当使用==或!=进行比较时,比较的是应用的值,而不是引用本身。
2.[]运算符用于访问string中的个别字符。
例如:char c = “abcdefd”[2]
C的值是c.
3.@符号:@”abcdefgh”
用@符号的好处是换码序列将不被处理。但是要想用双引号,使用””abcd””的形式。
例子:string str = @”””stop!””, he shout!”;
修饰符
作用
访问修饰符
Public
Private
Internal
protected
指定声明的类型和成员的可访问性
abstract
指示某个类只能是其他类的基类,虚基类。
Const
指定无法修改字段或局部变量的值,只能在声明时初始化。
Event
声明一个事件
Extern
指示外部实现此方法
Override
提供从基类继承的 虚拟成员 的新实现
Readonly
声明的字段只能在声明时或构造函数中初始化。
龙腾一族至尊龙骑