御2:域2

一如我们期待的那样,程序输出01。我们可以看到属性通过对方法的包装向程序员提供了一个友好的域成员的存取界面。这里的value是C#的关键字,是我们进行属性操作时的set的隐含参数,也就是我们在执行属性写操作时的右值。
  属性提供了只读(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中的虚属性。
  静态属性和静态方法一样只能存取类的静态域变量。我们也可以像做外部方法那样,声明外部属性。
Tags: 

延伸阅读

最新评论

发表评论