封装集合中的引用类型

时间:2011-01-21 09:10:39

标签: c# collections encapsulation indexer

我宣布了一个有几个属性的类

class Soil
{
  public double AnglePhi { get; set; }
  public double AngleDelta { get; set; }
  .
  .
  .
}

现在为了操作它们的集合,我构建了另一个专用类,仅仅是出于这个原因。

class Soils
{
  private const Byte numberOPredefined = 10;   
  private IList<Soil> soils;

  public Soil this[ushort i]
  {
    get { return new Soil() { AngleDelta = soils[i].AngleDelta, ... }; }
    set { if (i > numberOPredefined) soils[i] = value; }
  }
  .
  .
  .
}

这背后的逻辑是在某种程度上防止直接操纵每个Soil实例的属性。在getter中给出一个副本,在setter中请求一个“整个”土壤对象。

从我到目前为止的红色,其他解决方案可能是:
使土壤类不变,
返回一个ReadOnly List(但随后可以操作引用类型) 将Soil类转换为struct(简单),
使用一些逻辑(方法等)来扩充Soil类。

我想问一下上述“解决方案”是否具有任何价值,或者是否定义不明确。

这是我认为的典型情况,例如拥有引用类型集合并想要封装它们。在这些情况下,典型的思维框架是什么?

编辑:
好的,在阅读完答案后我将解决方案修改为

class Soil
{
  private readonly double _AnglePhi;
  public double AnglePhi { get { return _AnglePhi; } }

  private readonly double _AngleDelta;
  public double AngleDelta { get { return _AngleDelta; } }
  .
  .
}

class SoilCollection
{
  private List<Soil> _Soils;
  public IList<Soil> Soils { get { return _Soils.AsReadOnly(); } }
  .
  .
}

我认为Soil类需要内部逻辑,而不是另一个类。如果我发现任何缺点,我会发布。

4 个答案:

答案 0 :(得分:2)

您可以将Soil定义为 ValueObject ,然后在创建后它将是不可变的:

class Soil
{
  public Soil(double anglePhi, double angleDelta)
  {
      AnglePhi = anglePhi;
      AngleDelta = angleDelta;
  }

  public double AnglePhi { get; private set; }
  public double AngleDelta { get; private set; }
}

我认为最好将Soils重命名为SoilCollection。

答案 1 :(得分:2)

如果您希望Soil类型具有复制语义,请将其定义为结构。您应该通过将支持字段声明为只读并添加适当的构造函数使其不可变。

struct Soil
{
  private readonly double anglePhi;
  private readonly double angleDelta;

  public Soil(double phi, double delta) {
    this.anglePhi = phi;
    this.angleDelta = delta; 
  }

  public double AnglePhi { get { return anglePhi; } }
  public double AngleDelta { get { return angleDelta; } }
}

如果你把它保持为类,我就不会使用索引器来检索对象的副本。我宁愿使用一种方法来表明用户正在获取该对象的副本。并将其设为只读,就像上面的结构一样,就像类一样。这可能也会消除制作副本的需要。

答案 2 :(得分:1)

没有理由要在Soil类上同时实现setter和getter。您可以选择仅实现get,这将使Soil对象只读。

你显然必须有其他一些设置内部值的方法 - 可以在构造函数中完成。

例如:

class Soil
{
    private double m_anglePhi;

    public Soil( double anglePhi )
    {
        m_anglePhi = anglePhi;
    }

    public double AnglePhi 
    {
        get { return m_anglePhi; }
    }
}

答案 3 :(得分:1)

我建议:

1)使土壤类不可变。

2)使Soils类成为只读集合。 如同,从IList派生并声明add etc方法作为interfact的显式实现。

相关问题