限制访问器可访问性(C# 编程指南)

属性或索引器的 getset 部分称为访问器。 默认情况下,这些访问器具有与其所属属性或索引器相同的可见性或访问级别。 有关详细信息,请参阅可访问性级别。 不过,有时限制对其中某个访问器的访问是有益的。 通常,限制 set 访问器的可访问性,同时保持 get 访问器可公开访问。 例如:

private string _name = "Hello";

public string Name
{
    get
    {
        return _name;
    }
    protected set
    {
        _name = value;
    }
}

在此示例中,名为 Name 的属性定义 get 访问器和 set 访问器。 get 访问器接收该属性本身的可访问性级别(此示例中为 public),而对于 set 访问器,则通过对该访问器本身应用 protected 访问修饰符来进行显式限制。

备注

本文中的示例不使用自动实现的属性。 自动实现的属性提供了一种简洁的语法,用于在不需要自定义支持字段时声明属性。

对访问器的访问修饰符的限制

对属性或索引器使用访问修饰符受以下条件的制约:

  • 不能对接口或显式接口成员实现使用访问器修饰符。
  • 仅当属性或索引器同时具有 setget 访问器时,才能使用访问器修饰符。 这种情况下,只允许对其中一个访问器使用修饰符。
  • 如果属性或索引器具有 override 修饰符,则访问器修饰符必须与重写的访问器的访问器(如有)匹配。
  • 访问器的可访问性级别必须比属性或索引器本身的可访问性级别具有更严格的限制。

重写访问器的访问修饰符

重写属性或索引器时,被重写的访问器对重写代码而言必须是可访问的。 此外,属性/索引器及其访问器的可访问性都必须与相应的被重写属性/索引器及其访问器匹配。 例如:

public class Parent
{
    public virtual int TestProperty
    {
        // Notice the accessor accessibility level.
        protected set { }

        // No access modifier is used here.
        get { return 0; }
    }
}
public class Kid : Parent
{
    public override int TestProperty
    {
        // Use the same accessibility level as in the overridden accessor.
        protected set { }

        // Cannot use access modifier here.
        get { return 0; }
    }
}

实现接口

使用访问器实现接口时,访问器不一定有访问修饰符。 但如果使用一个访问器(如 get)实现接口,则另一个访问器可以具有访问修饰符,如下面的示例所示:

public interface ISomeInterface
{
    int TestProperty
    {
        // No access modifier allowed here
        // because this is an interface.
        get;
    }
}

public class TestClass : ISomeInterface
{
    public int TestProperty
    {
        // Cannot use access modifier here because
        // this is an interface implementation.
        get { return 10; }

        // Interface property does not have set accessor,
        // so access modifier is allowed.
        protected set { }
    }
}

访问器可访问性域

如果对访问器使用访问修饰符,则访问器的可访问性域由该修饰符确定。

如果未对访问器使用访问修饰符,则访问器的可访问性域由属性或索引器的可访问性级别确定。

示例

下面的示例包含三个类:BaseClassDerivedClassMainClass。 每个类的 BaseClassNameId 都有两个属性。 该示例演示在使用限制性访问修饰符(如 protectedprivate)时,BaseClassId 属性如何隐藏 DerivedClassId 属性。 因此,向该属性赋值时将调用 BaseClass 类中的属性。 将访问修饰符替换为 public 将使该属性可供访问。

该示例还演示了 DerivedClassName 属性的 set 访问器的限制性访问修饰符(例如 privateprotected)如何阻止访问派生类中的访问器。 在向该修饰符赋值时,它会生成一个错误,或者访问同名的基类属性(如果可访问)。

public class BaseClass
{
    private string _name = "Name-BaseClass";
    private string _id = "ID-BaseClass";

    public string Name
    {
        get { return _name; }
        set { }
    }

    public string Id
    {
        get { return _id; }
        set { }
    }
}

public class DerivedClass : BaseClass
{
    private string _name = "Name-DerivedClass";
    private string _id = "ID-DerivedClass";

    new public string Name
    {
        get
        {
            return _name;
        }

        // Using "protected" would make the set accessor not accessible.
        set
        {
            _name = value;
        }
    }

    // Using private on the following property hides it in the Main Class.
    // Any assignment to the property will use Id in BaseClass.
    new private string Id
    {
        get
        {
            return _id;
        }
        set
        {
            _id = value;
        }
    }
}

class MainClass
{
    static void Main()
    {
        BaseClass b1 = new BaseClass();
        DerivedClass d1 = new DerivedClass();

        b1.Name = "Mary";
        d1.Name = "John";

        b1.Id = "Mary123";
        d1.Id = "John123";  // The BaseClass.Id property is called.

        System.Console.WriteLine("Base: {0}, {1}", b1.Name, b1.Id);
        System.Console.WriteLine("Derived: {0}, {1}", d1.Name, d1.Id);

        // Keep the console window open in debug mode.
        System.Console.WriteLine("Press any key to exit.");
        System.Console.ReadKey();
    }
}
/* Output:
    Base: Name-BaseClass, ID-BaseClass
    Derived: John, ID-BaseClass
*/

注释

注意,如果将声明 new private string Id 替换为 new public string Id,则得到如下输出:

Name and ID in the base class: Name-BaseClass, ID-BaseClass Name and ID in the derived class: John, John123

请参阅