string和object类型是简单的引用类型,数组是隐式的引用类型,结构类型是值类型。我们创建的每个类都是引用类型。
类定义:
[internal或public] [abstract或sealed] class <name>
{
}
internal表示类只能在当前项目中访问,默认为internal;public表示类可以在任何地方访问(可由其它项目中的代码来访问,例如创建类库项目)。
abstract指定为抽象类,不能实例化,只能继承;sealed指定为密封类,不能继承,只能实例化。
接口定义:
[internal或public] interface <name>
{
}
接口成员的定义不允许使用访问修饰符,所有接口成员隐式为公共的,接口成员不能包含代码体、不能定义字段成员,不能用static、virtual、abstract或sealed定义接口成员,禁止类型定义成员。
继承:
在类名后面加上冒号,其后是基类名,且只能有一个基类。派生类的可访问性不能高于基类,内部类可以继承于公共基类,反之不行。
类继承于抽象类,就必须实现所继承的所有抽象成员。
类可以支持多个接口,若有基类,接口名必须在基类名之后,使用逗号分隔。
接口可以继承于多个接口。
if(myObj.GetType() == typeof(MyClass))
{
//说明myObj是类MyClass的一个实例
}
在实例化过程中base关键字指定使用基类中具有指定参数的构造函数,如:
public class MyClass : MyBaseClass
{
public MyClass() : base(5)
{
}
}
在调用指定的构造函数前,this关键字能够先调用当前类的非默认构造函数,如:
public class MyClass
{
public MyClass() : this(5, 6)
{
}
public MyClass(inti, int j)
{
}
}
接口、抽象类比较:
相同之处:接口和抽象类都不能直接实例化,但可以声明这些类型的变量,利用多态性把继承这两种类型的对象指定给它们的变量,然后使用这些类型的成员,但不能访问派生对象的其它成员。
不同之处:派生类只能继承一个基类,但可以使用多个接口;抽象类拥有抽象成员(无代码体,必须在派生类中实现,除非派生类也为抽象类)和非抽象成员(有代码体,也可以是虚拟的,这就可以在派生类中重写);接口成员无代码体,必须都在使用接口的类上实现;接口成员是公共的,抽象成员可以是私有的、受保护的、内部的等;接口不能包含字段、构造函数、析构函数、静态成员或常量。
浅度复制:未考虑引用类型成员,新对象中的引用成员就会指向源对象中相同成员引用的对象。
深度复制:复制值,而不复制引用。
关键字public、private(默认值)、protected、internal(只能由定义它的项目内部的代码访问)用来定义类成员的访问级别;结合使用protected internal表示只能由项目中派生类的代码来访问。
字段:
定义字段用标准的变量声明格式。(推荐)公共字段以PascalCasing形式(各单词首字母大写)命名,私有字段通常使用camelCasing形式(第一个单词首字母小写)命名。
字段使用readonly关键字,表示该字段只能在执行构造函数的过程中赋值,或由初始化赋值语句赋值,如public readonly int MyInt = 17;
方法:
方法使用标准函数格式、可访问性和可选的static修饰符来声明。在方法定义中可使用关键字virtual(方法可以重写)、abstract(仅用于抽象类,方法必须在非抽象的派生类中重写)、override(重写了一个基类方法,若方法被重写则必须使用此关键字)、extern(方法定义放在其它地方)。
例:
public class MyBaseClass
{
public virtual void DoSomething()
{
……
}
}
public class MyClass : MyBaseClass
{
public override void DoSomething()
{
……
}
}
使用了override,也可以使用sealed来指定在派生类中不能对这个方法做进一步的修改,即此方法不能由派生类重写,如:
public class MyClass : MyBaseClass
{
public override sealed void DoSomething()
{
……
}
}
属性:
与字段类似。声明举例:
private int myInt; //私有字段
public int MyIntProp //属性
{
get
{
return myInt;
}
set
{
myInt = value;
}
}
关键字get、set定义的两个块称为访问器,访问器前也可包含可访问修饰符,但访问器的可访问性不能高于它所属的属性。通过忽略get、set块其中的一个来创建只读或只写属性。
属性可以使用virtual、override和abstract关键字。
自动属性,如public int MyIntProp { get; set; }不用定义字段,只能通过属性访问数据,必须包含get和set存取器,可以改变存取器的可访问性。
隐藏基类方法:
基类的成员是虚拟的,就可以用override关键字重写,但无论基类成员是否为虚拟,都可以隐藏其实现代码,如:
public class MyBaseClass
{
public [virtual] void DoSomething()
{
//MyBaseClass implementation
}
}
public class MyClass : MyBaseClass
{
new public void DoSomething() //不带new也可,但会产生一个警告
{
// MyClass implementation
}
}
MyClassobj = new MyClass();
MyBaseClass baseObj;
baseObj = obj;
baseObj.DoSomething(); //此时执行的是MyBaseClass的实现代码,但若不是隐藏基类方法,而是重写基类虚函数,执行的则是MyClass的实现代码
接口要隐藏从基接口中继承的成员,也可以用关键字new来定义它们。
可以通过base关键字调用基类的实现代码,同样,this关键字引用的是当前的对象实例,两关键字不能在静态成员中使用。
嵌套的类型定义:除了在名称空间中定义类型(如类)外,还可以在其它类中定义它们,这样就可以在定义中使用各种访问修饰符,也可以使用new关键字来隐藏继承于基类的类型定义。
接口的实现:
实现接口的类必须包含该接口所有成员的实现代码,并且必须是公共的;可以使用virtual或abstract来实现接口成员,还可以在基类上实现接口成员;基类中把实现代码定义为虚拟,派生类就可以重写它,派生类也可使用new来隐藏一个基类成员。
public interface MyInterface
{
void DoSomething();
void DoSomethingElse();
}
public class MyClass : MyInterface
{
void MyInterface. DoSomething() //显示实现接口成员
{
}
public void DoSomethingElse() //隐式实现接口成员
{
}
}
MyClass obj = new MyClass();
MyInterface myInt = obj;
myInt. DoSomething(); //显示实现的接口成员只能这样来访问
obj. DoSomethingElse(); //除上一种方法外,隐式实现的接口成员还可以这样来访问
部分类定义:
把类的定义放在多个文件中,需在包含部分类定义的每个文件中对类使用partial关键字;应用于部分类的接口也会应用于整个类;可以在一个或多个部分类定义文件中包含基类,若在多个定义文件中指定基类,就必须是同一个基类。
部分类可以定义部分方法。部分方法在一个部分类中定义(没有方法体),在另一个部分类中实现,在这两个部分类中都要使用partial关键字。
部分方法总是私有的,不能有返回值,参数可以是ref参数、不能是out参数,不能使用virtual、abstract、override、new、sealed和extern修饰符,可以是静态的。
public partial class MyClass
{
partial void DoSomethingElse();
public void DoSomething
{
……
DoSomethingElse();
……
}
}
public partial class MyClass
{
partial void DoSomethingElse()
{
……
}
}
部分方法的重要性体现在编译代码时。当删除部分代码的全部实现代码(或注释掉这部分代码)时,编译器会完全删除该方法以及对该方法的所有调用。