sealed关键字
如果我们将类标记为sealed,编译器将不会允许我们从这个类型派生。(c#结构总是隐式密封的。因此,我们永远不可以从结构继承结构,从类继承结构或从结构继承类。结构只能用于建模独立的、用户定义的数据类型。如果希望是is-a关系,就必须使用类。)
使用base关键字控制基类的创建
protected关键字
派生类型不再需要使用公共方法或属性来间接访问数据了。当然,可能的坏处在于:如果派生类型有权直接访问其父类内部数据,有可能会偶尔绕过公共属性内设置的既有业务规则。当定义受保护成员时,也就创建了一种父类和子类之间的信任级别,编译器不会捕获任何违背类型业务规则的异常。
包含/委托编程
class benefitpackage
{
public double computepaydeduction()
{ return 125.0; }
}
partial class employee
protected benefitpackage empbenefits=new benefitpackage();
public double getbenefitcost()
{ return empbenefits.computepaydeduction(); }
public benefitpackage benefits
{ get { return empbenefits; }
set { empbenefits=value; }
}
.......
嵌套类型
public class outerclass
//公共嵌套类型可以被任何人使用
public class publicinnerclass { }
//私有嵌套类型只可以被包含类的成员使用
public class privateinnerclass { }
嵌套类型的特征:
通过嵌套类型可以完全控制内部类型的访问级别,也就是可以声明为私有的(回忆一下,非嵌套类不能使用private关键字来声明)。
由于嵌套类型是包含类的成员,所以它可以访问包含类的私有成员。
通常,嵌套类型只用做外部类的辅助方法,而不是外部世界所准备的。
//employee嵌套benefitpackage
public partial class employee
// benefitpackage嵌套benefitpackagelevel
public class benefitpackage
{
public enum benefitpackagelevel
{ standard,gold,platinum }
}
public double computepaydeduction()
{ return 125.0 }
在这种嵌套关系里需要注意如何使用枚举:
employee.benefitpackage.benefitpackagelevel mybenefitlevel=employee.benefitpackage.benefitpackagelevel.platinum;
virtual和override关键字
多态为子类提供了一种方式,使其可以定义为由其基类定义的方法,这种过程叫做方法重写。
poblic virtual void givebonus(float amount)
{ pay+=amount ; }
......
用virtual关键字标记的方法成为虚方法。
如果子类希望改变虚方法的实现细节,就必须使用override关键字。
class salesperson:employee
{ .......
//销售人员的奖金受销量的影响
public override void givebonus(float amount)
{
int salesbonus=0;
if(numberofsales>=0&&numberofsales<=100)
salesbonus=10;
else
{ if(numberofsales>=101&&numberofsales<=200)
salesbonus=15;
else
salesbonus=20;
}
base.givebonus(amount*salesbonus);
}
class manager:employee
public override void givebonus(float amout)
{ base.givebonus(amount);
random r=new random();
numberofoptions+=r.next(500);
密封虚成员
{ ........
public override sealed void givebonus(float amount)
{ ....... }
sealed class ptsalesperson:salesperson
public ptsalesperson(string fullname,int age,int empid,float currpay,string ssn,int numbofsales)
:base(fullname,age,empid,currpay,ssn,numbofsales)
{ }
// 编译器错误!不能在ptsalesperson类中重写这个方法,因为它是被密封的
{ }
抽象类
由于很多基类都是比较模糊的尸体,好的设计师会防止在代码中直接创建新的employee对象。
abstract partial class employee
{ ........ }
构建多态接口
成员投影
基类/派生类的转换规则
as关键字
//我们不能强制转换frank为hexagon,但编译没问题
hexagon hex=(hexagon)frank;
//使用“as”来测试兼容性
hexagon hex2=frank as hexagon;
if(hex2==null)
console.writeline("sorry,frank is not a hexagon...");
is关键字
除了is关键字,c#语言还提供了is关键字来测试两个项是否兼容。然而,和as关键字不同的是,如果类型不兼容,is关键字就返回false而不是null引用。
超级父类:system.object
system.object的核心成员
equals() 默认情况下,如果被比较的项指向内存中同一个项,则方法会返回true。因此,equals()用于比较对象引用,而不是对象的状态。一般情况下,这个方法被重写为:如果被比较的对象有相同的内部状态值(也就是基于值的语义),则返回true。要知道,如果重写equals(),则还需要重写gethashcode(),因为这些方法在内部用于hashtable类型从容器读取子对象。valuetype类为所有结构重写了该方法,它们进行的比较是基于值的。
finalize() 这个方法(在重写后)在对象销毁之前被调用来释放所分配的资源。
gethashcode() 这个方法返回int来标识指定的对象实例。
tostring() 这个方法是用<namespace>,<type name>格式(叫做完全限定名)返回对象的字符串表示。这个方法可以被子类重写来返回名称/值对的标识字符串以表示对象的内部状态,而不是它的完全限定名。
gettype() 这个方法返回type对象,它完整描述当前指向的对象。简而言之,这是所有对象都可用的运行时类型标识方法。
memberwiseclone() 这个方法的作用是逐个成员地返回当前对象的副本,通常用于克隆对象。