我正在尝试创建一个.NET API,它包装并与第三方C API接口。因此,API的语义如下:
有一个属性表示二进制文件中的字符串列表。在具有零条目的列表的此属性之间存在区别,在这种情况下,该属性将被写入具有空列表的文件;并且列表被完全省略,在这种情况下,属性将从文件中省略。
在我目前的设计中,我使用的是这样的东西:
public class InfoWrapper
{
// Use an IList<T> to avoid running afoul of FxCop
// rule CA1002: Do not expose generic lists.
public IList<string> ItemsContainer { get; set; }
}
当然,这样做可以让我区分“未设置”和“空列表”情况,但真正的问题是它会触发另一个FxCop警告,CA2227:集合属性应该是只读的。我需要能够允许用户将属性设置为null
值,如果他们在将其设置为null
后改变主意,则可能会返回列表。我可以使用一对方法(例如,DeleteItemsContainer()
和CreateNewItemsContainer()
)将属性设置为只读,但实际上,我需要以相同的方式处理这些属性中的几个。每个属性添加两个方法会大大混乱API。这里有什么更好的方法?
N.B。我意识到我可以压制FxCop警告并完成它,并且这些规则只是一组建议。但是,如果可能的话,我希望保持这些准则。
答案 0 :(得分:1)
我认为你混淆(或询问)两个问题:返回null
与空集合,以及让公共setter触发FxCop警告。无论类型是null
还是List
,您都可以返回IList
,因此没有问题。
如果您想避免关于公共setter的FxCop警告,您需要将setter设为私有,并提供另一种设置该属性值的方法。您可以通过IList
的构造函数传递InfoWrapper
,或者如果有意义,只需在构造函数中创建列表并在构造之后将所有项添加到其中。
答案 1 :(得分:0)
首先,属性必须是只读的,即没有setter。但即便如此,您仍会收到另一个FxCop警告,因为用户仍然可以修改该集合。
摆脱FxCop警告的一种简洁方法是将属性的定义从返回IList<T>
更改为返回IEnumerable<T>
。
像这样:
public IEnumerable<string> StringList { get; set; }
如果您可以不使用Count
等属性和索引器,则使用IEnumerable
有助于确保类用户不会弄乱列表内容。
(顺便说一句,在命名属性时,建议不要使用术语“String”或“List”。“String”不表示属性的语义,“List”表示应该是的集合类型封装的)