【问题标题】:ICollection property and encapsulationICollection 属性和封装
【发布时间】:2018-06-14 11:26:44
【问题描述】:

考虑到我想要封装它们,为我的属性使用接口是不好的做法吗?

public class Order
{
    private readonly ICollection<OrderItem> _orderItems;
    public IReadOnlyCollection OrderItems => _orderItems; // not possible without ToList
}

没有简单的方法来公开它,因为如果不首先使用ToList,就无法从ICollection 转换为IReadOnlyCollection 或IEnumerable,这涉及复制整个集合。

我应该将其定义为:

private readonly Collection<OrderItem> _orderItems;

或

private readonly HashSet<OrderItem> _orderItems;

或

private readonly List<OrderItem> _orderItems;

改为?

【问题讨论】:

  • 始终使用尽可能小的分母。即,对于方法或构造函数中的参数,请使用 IEnmuerable&lt;T&gt;,除非您需要更专业的接口,即 .Count 或需要 Add/Remove 方法等。作为返回时间,最低常用值取决于您的意图。你希望人们改变结果吗?使用IList&lt;T&gt; 或ICollection&lt;T&gt; 不想让用户操作它? IEnumerable&lt;T&gt; 并且它可能是可迭代的(即不立即执行)。或者返回T[],如果它应该更明确地表明它是一个数组而不是任何通用的可枚举/迭代器
  • @Tseng 是的,这里的问题更多是关于在私有字段中使用ICollection,以便以后将其公开为IReadOnlyCollection。除此之外,我通常按照你说的去做。

标签: c# domain-driven-design


【解决方案1】:

您应该遵循的规则是私有成员仅对定义它们的类可见,因此您可以将类型定义为List&lt;T&gt; 或Hashset&lt;T&gt; 或Collection&lt;T&gt;,其他使用您的类程序集的开发人员不会如果您稍后修改类型,则会受到重大更改的影响。

只要您知道Hasset&lt;T&gt; vs List&lt;T&gt; 和List&lt;T&gt; vs Collection&lt;T&gt; 之间的区别,您就可以选择您在问题中提出的三个备选方案之一。

因此,如果您不想在OrderItems 实现中调用ToList(),请删除接口ICollection&lt;OrderItem&gt; 作为您的private 字段类型并使用具体类。

【讨论】:

    【解决方案2】:

    您可以编写自己的扩展来将 ICollection 转换为 IReadOnlyCollection

    public static class CollectionExtensions
    {
        public static IReadOnlyCollection<T> AsReadOnly<T>(this ICollection<T> source)
        {
            if (source == null)
            {
                throw new ArgumentNullException("source");
            }
            return source as IReadOnlyCollection<T> ?? new ReadOnlyCollectionAdapter<T>(source);
        }
        sealed class ReadOnlyCollectionAdapter<T> : IReadOnlyCollection<T>
        {
            ICollection<T> source;
            public ReadOnlyCollectionAdapter(ICollection<T> source) { this.source = source; }
            public int Count { get { return source.Count; } }
            public IEnumerator<T> GetEnumerator() { return source.GetEnumerator(); }
            IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
        }
    }
    

    【讨论】:

    • ToList(返回 IReadOnlyCollection)已经是一个扩展方法。所以我不知道你为什么需要另一种扩展方法?
    • 我觉得这太hackish了,而且做这样的事情有点代码味道。
    • @CodeNotFound,ToList 涉及复制整个集合,它解决了更通用的任务,而这个扩展只专注于提供 IReadOnlyCollection
    猜你喜欢
    • 2011-02-23
    • 1970-01-01
    • 2015-10-17
    • 2021-11-17
    • 1970-01-01
    • 2014-07-26
    • 2013-01-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多