具体 class 实现中的 IEnumerable 与 List

IEnumerable versus List in a concrete class implementation

我正在编写一个 class 金融建模库。

我想使用接口定义模型以创建用于测试的抽象,并可能在以后添加新的具体 classes。

我正在为如何定义事物列表而苦苦挣扎,以便稍后可以在具体的列表中添加这些列表 class。

例如,如果我将一个接口定义为在我的模型中有一个费用列表,名为

IEnumerable 费用 {get;设置;}

然后想创建一个名为 ABCModel 的具体 class,其中包含一个具体的 XYZExpense 列表,实施列表的最佳方式是什么,以便我可以轻松地向列表中添加更多项目?

我无法将列表转换为 IEnumerable。

例如:

 public interface IFinancialModel
{
    IEnumerable<IExpense> Expenses { get; }
    IEnumerable<IRevenue> Revenue { get; }
    IEnumerable<IAsset> Assets { get; }
    IEnumerable<ILiability> Liabilities { get; }
}

我需要一个名为 public class 的具体 class FinancialModel : IFinancialModel

并能够添加具体项目。

我应该创建自己的 'Add' 方法吗?理想情况下,我想利用内置的列表功能而不是重新发明轮子。

这取决于你真正想做什么。不推荐拥有 ListIList 属性,因为你可以用它做任何事情(如 ClearAdd 等等)而无需拥有 class 知道关于它。这不利于封装。您将无法对更改执行某些操作(例如设置脏标志、触发已更改的事件或进行验证)。

IEnumerable是个不错的选择。

您可以添加 setter,但您不应引用设置为 属性 的值。它可以是您不想引用的任何内容,例如 Linq 查询甚至数据库查询。你只想要物品。 (还要考虑到来自外部的对集合的引用可以分配给其他实例,当它在那里更改时会导致非常糟糕的副作用,但不应在此处更改。)

// example implementation with a setter
private List<IExpense> expenses 

public IEnumerable<IExpense> Expenses 
{ 
  get { return expenses; }
  set { expenses = value.ToList(); }
}

或者,您可以实现自己的 AddAddRangeRemoveClear 等方法。但是,如果主要用例是一次设置所有项目,则只能有一个 SetExpenses 方法,这与我之前显示的 属性 上的 setter 相同。您可以考虑将其作为数组保存在内部。

您要找的是IList<T>。这是一个允许您在隐藏实际列表实现的同时公开列表的接口。例如:

interface IFinancialModel {
    IList<IExpense> Expenses { get; }
}

然后使用满足您需求的列表来实施。例如:

class FinancialModel : IFinancialModel {
    private IList<IExpense> _expenses = new List<IExpense>();
    IList<IExpense> Expenses { get { return _expenses; } }
}

不过我同意@Stefan 的观点,公开列表会破坏封装,通常应避免这样做。