在 API 代码中,对列表类型 C# 属性使用私有 setter 是个好主意吗?
我正在寻找对某事的意见。考虑来自名为 SomeApiObject
的类的以下代码:
// Property with private setter
public IList<string> SomeList
{
get;
private set;
}
// Constructor
public SomeApiObject()
{
SomeList = new List<string>();
}
通过此设置,SomeApiObject
类的用户无法重新分配 SomeList
属性,但是他们< em>可以做的是使用Add()
、Remove()
和Clear()
等方法操作现有列表代码>.
这种模式的优点是保证该属性永远不会为 null,这对于用户使用 API 来说是一个非常方便的假设,因为这意味着用户始终可以迭代列表、获取列表的大小或添加到列表中,而无需检查 null
。
我看到了一些缺点。其一,对于用户来说,列表旨在通过操作其内容来写入并不一定是显而易见的。另一方面,我可以设想这样的情况:操作列表在语法上不太方便,或者性能可能比分配新列表更差。
我对此持观望态度,正在寻求意见。
- 对于 API 用户来说,潜在的缺点是否太令人讨厌了?
- 保证永远不会
null
是否像我想象的那样是一个很好的功能?
编辑:
我已经确信使用某种“永不为空”模式的好处。我更感兴趣的是有人唱反调,并向我展示为什么从 API 用户的角度来看,在一个旨在被操纵的列表上有一个私人 setter 可能会令人烦恼和/或令人望而却步。
我不久前发布了一个 .NET API 包装器,到目前为止,一些用户对如何为此类属性分配值表示困惑。
I'm looking for an opinion on something. Consider the following code from a class called SomeApiObject
:
// Property with private setter
public IList<string> SomeList
{
get;
private set;
}
// Constructor
public SomeApiObject()
{
SomeList = new List<string>();
}
With this setup, users of the class SomeApiObject
cannot reassign the SomeList
property, but what they can do is to manipulate the existing list by using methods such as Add()
, Remove()
, and Clear()
.
The upside of this pattern is that the property is guaranteed to never be null
, which can be a very convenient assumption to make as a user is working with the API, since it means the user can always iterate over the list, get the list's size, or add to it without ever having to check for null
.
I see a few downsides. For one, it's not necessarily obvious to a user that the list is intended to be writable by manipulating its contents. For another, I could envision situations where manipulating the list is less convenient syntactically or possibly worse in performance than assigning a new list.
I'm on the fence with this one, and I'm seeking opinions.
- Are the potential downsides just too obnoxious for a user of the API?
- Is the guarantee of never being
null
as nice a feature as I think it is?
EDIT:
I'm already convinced of the benefits of using some sort of "never null" pattern. What I'm more interested in is for someone to play devil's advocate and show me why having a private setter on a list that's meant to be manipulated might be annoying and/or prohibitive from the perspective of a user of the API.
I released a .NET API wrapper some time ago, and so far a few users have expressed confusion over how to assign values to properties like this one.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
永不为空是一个很好的设计特性。关于仅将列表公开为只读属性,这是我最喜欢的指南书中的建议:http://www.amazon.com/Framework-Design-Guidelines-Conventions-Libraries/dp/0321545613
虽然更好的方法不是允许外部调用者直接操作对象的状态并使类不可变:
Never null is a good design feature. In regards to only exposing lists as read only properties this is put forward as a recommendation in the my favorite guidelines book: http://www.amazon.com/Framework-Design-Guidelines-Conventions-Libraries/dp/0321545613
Though a better approach is not to allow external callers to manipulate the state of your object directly and to make the class immutable:
如果您想消除用户获取列表引用然后以非预期方式在外部操作它的可能性,那么您应该将属性更改为仅返回
IEnumerable
。这将允许用户仍然使用该集合(也将支持 linq)并保护该集合免受外部操作。
If you want to remove the possibility of users getting a reference to the list then simply manipulating it externally in an unintended manner, then you should change your property to only return an
IEnumerable
instead.This will allow the user to still make use of the collection (also will support linq) and will protect the collection from external manipulation.
需要考虑的另一点是,问题取决于对象是“拥有”列表(组合)还是“拥有”列表(聚合)。如果对象拥有该列表,则 setter 应该是私有的;如果它仅具有来自另一个对象的列表,则设置器可能是公共的。
组合情况中的一个复杂情况(除了列表被分配空值的可能性之外)是公共 setter 导致类放弃对列表实现的所有控制。例如,假设您有这样的实现:
现在假设在后续版本中,您想要使用实现
IList
的SomeSpecializedList
,而不是List< ;字符串>
。您可以轻松重构:只有私有实现发生了变化;该类的用户不受影响。但如果 setter 是公共的,客户端可能会将任何 IList 实例传递到 SomeList 中,这将是一个重大更改。
One other point to consider is that the question depends on whether the object "owns" the list (composition) or "has" the list (aggregation). If the object owns the list, the setter should be private; if it simply has the list from another object, the setter could possibly be public.
A complication in the composition case (other than the possibility of the list being assigned a null value) is that a public setter causes the class to cede all control over the implementation of the list. Suppose, for instance, you have the implementation:
Now suppose in a subsequent version, you want to use
SomeSpecializedList
, which implementsIList<string>
, instead ofList<String>
. You could easily refactor:Only the private implementation has changed; users of the class are unaffected. But if the setter were public, the client could have potentially passed any IList instance into SomeList, and this would be a breaking change.
这取决于具体情况。在某些情况下,拥有一个空列表可能是有意义的,但在其他情况下则没有那么多意义。你必须问自己这是否有意义。 .net 本身就是两种方式。
it depends on the situation. in some cases, it might make sense to be able to have a null list, in other not so much. you have to ask yourself if it makes sense. .net itself does it both ways.
尽管我很讨厌这样说,但这实际上取决于您想要使用 API 做什么。如果您想向用户提供他们可以使用的集合,那么@Matthew 的答案是合适的。如果您想隐藏集合或只允许某些操作(例如
添加
、删除
等),那么您可以隐藏集合并公开一个外观集合:希望这有帮助。
As much as I hate saying this, it really depends on what you're trying to do with your API. If you want to provide the user with a collection that they can work with, then @Matthew's answer is appropriate. If you want to hide the collection or only allow certain actions to be permitted (like
Add
,Remove
, etc.), then you could hide the collection and expose a facade to the collection:Hope this helps.