C# 属性显式设置与覆盖获取

C# property explicit set versus override get

简而言之:编写基本 class 属性,我们更喜欢显式 set 方法还是重写 get 方法?

我的主页有一个基础 class。它实现了几个"features";一些实例可能想要禁用该功能,这在设计时是已知的(即它不会改变)。基础 class 看起来像这样:

public class MyPage : System.Web.UI.Page
{
  void Method()
  {
    if (Feature1)
      DoSomething1();
  }
}

问题是:以下两种定义 Feature1 属性的方法中哪一种是首选:

// In MyPage class
private bool _feature1 = true;
protected bool Feature1
{
  get { return _feature1; }
  set { _feature1 = value; }
}

// In Derived page class, somewhere early
Feature1 = false;

对比:

// In MyPage class
protected virtual bool Feature1
{
  get { return true; }
}

// In Derived page class
protected override bool Feature1
{
  get { return false; }
}

在第一种情况下,该属性具有显式 set 供派生 Page 调用;在第二种情况下,该属性没有 set,而是允许派生的 Page 覆盖 get。我们有偏好吗?

与我的 Pages 相比,此选择适用于更一般的 C# 案例,但它表明我在某些方面受到限制(例如,我没有做 new,我不负责构造函数, ...)

使用自动 属性 并在构造函数中设置值。

protected bool Feature1 { get; set; } 

// Your Constructor    
public YourClassName(bool featureState)
{
     Feature1 = featureState;
}

最好也覆盖 set。由于它在派生 class 中没有功能,您或其他人可能想设置在这种情况下无效的值,然后在几天或几周后您想知道为什么它设置 Feature1 不是按需工作。所以如果有人试图设置它,你最好抛出一个异常:

override bool Feature1
{
    get { return true; }
    set { throw new InvalidOperationException("In this implementation 'Feature1' is read-only."); }
}

示例:

class Program
{
    static void Main(string[] args)
    {
        bool baseFeature1a = new Base1().Feature1; // false
        bool baseFeature1b = (new Derived1() as Base1).Feature1; // true

        bool baseFeature2a = new Base1().Feature2; // false
        bool baseFeature2b = (new Derived1() as Base1).Feature2; // true
    }
}

class Base1
{
    private bool feature2 = false;

    public virtual bool Feature1
    {
        get { return false; }
    }

    public virtual bool Feature2
    {
        get { return feature2; }
        protected set { feature2 = value; }
    }
}

class Derived1 : Base1
{
    public Derived1()
    {
        Feature2 = true;
    }

    public override bool Feature1
    {
        get { return true; }
    }
}

根据您的描述,听起来您确实打算将其设为只读字段。

在这种情况下,只定义 属性 的 get 一半,并在派生的 类 中覆盖它是合适的。

这也有一个 compile-time 错误的好处,而不是 运行-time 错误,如果有人尝试设置它。

当然,如果它不是应该是只读的,那么你需要实现setter。