我想知道在类中公开集合的推荐方法是什么,以及它与使用NHibernate实体时做同样事情的方式有什么不同。
让我解释一下......我的类暴露集合属性时从未遇到过具体问题,如:
IList<SomeObjType> MyProperty { get; set; }
将setter设置为protected或private会让我有时更多地控制我想要处理集合的方式。 我最近遇到了Davy Brion撰写的这篇文章:
http://davybrion.com/blog/2009/10/stop-exposing-collections-already/
Davy,明确建议将集合作为IEnumerables而不是让我们说Lists,以禁止用户选择直接操作这些集合的内容。我可以理解他的观点,但我并不完全相信,通过阅读他的帖子上的评论,我不是唯一的。
当涉及NHibernate实体时,以他提出的方式隐藏集合是特别有意义的,特别是当级联到位时。我希望完全控制会话及其集合中的实体,并且为集合属性公开AddXxx和RemoveXxx对我来说更有意义。
问题是怎么做?
如果我将实体的集合作为IEnumerables我没有办法向它们添加/删除元素而不通过执行ToList()将它们转换为Lists,这会产生一个新的列表,因此没有任何东西可以保留,或者将它们转换为Lists由于代理和延迟加载,这是一种痛苦。
总体思路是不允许检索实体并直接操作其集合(add.remove元素),而只是通过我公开的方法,同时遵守集合持久性的级联。
非常感谢您的建议和想法。
答案 0 :(得分:8)
怎么样......
private IList<string> _mappedProperty;
public IEnumerable<string> ExposedProperty
{
get { return _mappedProperty.AsEnumerable<string>(); }
}
public void Add(string value)
{
// Apply business rules, raise events, queue message, etc.
_mappedProperty.Add(value);
}
如果您使用NHibernate映射到私有字段,即可以使用此解决方案。 _mappedProperty。您可以在访问和命名策略文档here中阅读有关如何执行此操作的详细信息。
事实上,我更喜欢像这样映射我所有的课程。开发人员更好地决定如何定义类的公共接口,而不是ORM。
答案 1 :(得分:0)
如何将它们公开为ReadOnlyCollection?
IList<SomeObjType> _mappedProperty;
return new ReadOnlyCollection<SomeObjType> ExposedProperty
{
get
{
return new ReadOnlyCollection(_mappedProperty);
}
}
答案 2 :(得分:0)
我正在使用NHibernate,我通常将集合保留为ISet并使setter受到保护。
ISet<SomeObjType> MyProperty { get; protected set; }
我还为需要它们的集合属性提供AddXxx和RemoveXxx。在大多数情况下,这对我来说非常令人满意。但我要说的是,有些情况下允许客户端代码直接向集合中添加项目。
基本上,我所看到的是,如果我在客户端代码中遵循"Tell, Don't Ask"的原则,而不必担心在我的域对象属性上强制执行严格的访问约束,那么我总是以一个好的设计。