与派生类共享字段

时间:2017-03-14 15:06:09

标签: c#

我在C#中有一个抽象类:

public abstract class DataSeed {

  private Context _context;

  private IReadOnlyList<String> _languages = new List<String> { "en", "fr" };

  private const String DRIVE = "http://mydriveurl";

}

仅与派生类共享这3个字段的最佳方法是什么:

public MyDataSeed : DataSeed {
}

我应该使用protected,protected并将它们转换为属性等吗?

请注意:

  1. DRIVE是常数,无法更改;
  2. _context应该在派生类构造函数中初始化,不应该在它之后再次初始化。
  3. _languages是一个无法更改的列表。

5 个答案:

答案 0 :(得分:2)

我建议这样的事情:

public abstract class DataSeed {
  // const, but can be used in any descendant class
  protected const String DRIVE = "http://mydriveurl";

  // _context ... should not be initialize again after it (constructor)
  protected Context Context {
    get; // in case of C# 6.0+ we can drop the set
  } 

  // _context should be initialized in the derived class constructor
  protected DataSeed(Context context) {
    if (null == context)
      throw new ArgumentNullException("context", 
        "context should be initialized in the derived class constructor");

    // C# 6.0+ feature: assigning to read only property within a costructor
    Context = context;    
  }

  // _languages is a list that cannot be changed:
  //  if you insist on list, IReadOnlyList<string> is a possible choice
  //  if "cannot be changed" dominates - IReadOnlyCollection<string>
  // static: it seems that you don't want to have _languages per each instance
  protected static readonly IReadOnlyCollection<String> _languages = 
    new List<String> { "en", "fr" }.AsReadOnly();
}

编辑:如果是C#5.0-由于Abion47在评论中出现问题,我们可以确保_context无法分配readonly但是在构造函数的帮助下{{1 }}

  // _context ... should not be initialize again after it (constructor)
  private readonly Context _context;

  protected Context Context {
    get {
      return _context;
    }
  } 

  // _context should be initialized in the derived class constructor
  protected DataSeed(Context context) {
    if (null == context)
      throw new ArgumentNullException("context", 
        "context should be initialized in the derived class constructor");

    // assigning to read only field within a costructor
    _context = context;    
  }

答案 1 :(得分:1)

注意1:如果您的所有属性和方法的访问范围都低于您的类,则应考虑您的类是否应共享相同的范围。 internal就足够了。

注意2.如果您的实际使用范围相似,我会将DRIVE置于静态类中,并根据以下答案将其他2个属性转换为界面。

1&amp; 3已经由您的数据类型强制执行,但有人可以始终使用new创建可以更改的其他属性。

2那是由儿童班组成的。您不能从子类中的父类强制构造函数化妆。您只能在父级中创建一个构造函数,子级可以继承该构造函数。

答案 2 :(得分:0)

如果我正确理解您的需要,我可以使用两个字段的私有设置器将它们切换到受保护的属性。

对于常量我只是将其设置为受保护,以便派生类可以访问它。

答案 3 :(得分:0)

您可以使用以下内容,允许子类访问属性,而不允许它们实例化值。

public abstract class DataSeed {

  protected Context _context { get; set; }

  protected IReadOnlyList<String> _languages  { get; private set; } = new List<String> { "en", "fr" }.AsReadOnly();

  protected const String DRIVE = "http://mydriveurl";

}

答案 4 :(得分:0)

要将字段公开给派生类,请将它们标记为protected而不是private。此外,您可以将_context标记为readonly,以便它只能在构造函数中初始化,然后将protected构造函数添加到派生类调用的DataSeed。< / p>

此外,如果派生类将其强制转换为_languagesList仍然容易受到攻击。相反,您应该考虑使用ReadOnlyCollection并将其标记为readonly

public abstract class DataSeed 
{
    protected const String DRIVE = "http://mydriveurl";
    protected readonly Context _context;

    protected readonly ReadOnlyCollection<string> _languages = 
                                     (new List<string> { "en", "fr" }).AsReadOnly();

    protected DataSeed()
    {
        _context = someValue;
    }
}

public MyDataSeed : DataSeed 
{
    public MyDataSeed()
        : base()
    {
        // Other constructor-y stuff
    }
}