属性提供了只读(get),只写(set),读写(get和set)三种接口操作。对域的这三种操作,我们必须在同一个属性名下声明,而不可以将它们分离,看下面的实现:
classMyClass
{
privatestringname;
publicstringName
{
get{returnname;}
}
publicstringName
{
set{name=value;}
}
}
上面这种分离Name属性实现的方法是错误的!我们应该像前面的例子一样将他们放在一起。值得注意的是三种属性(只读,只写,读写)被C#认为是同一个属性名,看下面的例子:
classMyClass
{
protectedintnum=0;
publicintNum
{
set
{
num=value;
}
}
}
classMyClassDerived:MyClass
{
newpublicintNum
{
get
{
returnnum;
}
}
}
classTest
{
publicstaticvoidMain()
{
MyClassDerivedMyObject=newMyClassDerived();
//MyObject.Num=1;//错误!
((MyClass)MyObject).Num=1;
}
}
我们可以看到MyClassDerived中的属性Num-get{}屏蔽了MyClass中属性Num-set{}的定义。
当然属性远远不止仅仅限于域的接口操作,属性的本质还是方法,我们可以根据程序逻辑在属性的提取或赋值时进行某些检查,警告等额外操作,看下面的例子:
classMyClass
{
privatestringname;
publicstringName
{
get{returnname;}
set
{
if(value==null)
name="Microsoft";
else
name=value;
}
}
}
由于属性的方法的本质,属性当然也有方法的种种修饰。属性也有5种存取修饰符,但属性的存取修饰往往为public,否则我们也就失去了属性作为类的公共接口的意义。除了方法的多参数带来的方法重载等特性属性不具备外,virtual,sealed,override,abstract等修饰符对属性与方法同样的行为,但由于属性在本质上被实现为两个方法,它的某些行为需要我们注意。看下面的例子:
abstractclassA
{
inty;
publicvirtualintX
{
get{return0;}
}
publicvirtualintY
{
get{returny;}
set{y=value;}
}
publicabstractintZ{get;set;}
}
classB:A
{
intz;
publicoverrideintX
{
get{returnbase.X+1;}
}
publicoverrideintY
{
set{base.Y=value<0?0:value;}
}
publicoverrideintZ
{
get{returnz;}
set{z=value;}
}
}
这个例子集中地展示了属性在继承上下文中的某些典型行为。这里,类A由于抽象属性Z的存在而必须声明为abstract。子类B中通过base关键字来引用父类A的属性。类B中可以只通过Y-set便覆盖了类A中的虚属性。
静态属性和静态方法一样只能存取类的静态域变量。我们也可以像做外部方法那样,声明外部属性。
最新评论