Krzysztof's建议是否适用于构造函数?如果是这样,你如何正确实施?
我们建议对输出和属性使用Collection,ReadOnlyCollection或KeyedCollection,并使用IEnumerable,ICollection,IList作为输入。
例如,
public ClassA
{
private Collection<String> strings;
public Collection<String> Strings { get { return strings; } }
public ClassA(IEnumerable<String> strings)
{
this.strings = strings; // this does not compile
this.strings = strings as Collection<String>; // compiles (and usually runs?)
}
}
答案 0 :(得分:5)
你应该避免向下倾斜;在您的示例中,我建议您的构造函数参数的类型应与您的成员数据的类型匹配(应该相同)(即 Collection<String>
或 IEnumerable<String>
)。
或者有Marc的解决方案,这是不同的:因为Marc的解决方案意味着您的成员数据不仅是一个不同的类型,它也是一个不同的实例(即如果您修改成员数据,那么您正在修改原始集合,而不是编辑原始集合本身;类似地,如果在复制后修改了原始集合,则本地副本/成员数据不包括对原始集合的后续更改。
答案 1 :(得分:4)
您不应该使用as
版本 - 您应该接受并存储可重复的内容,例如IList<T>
,或者创建新的本地数据集合:
this.strings = new Collection<string>();
foreach(string s in strings) { this.strings.Add(s); }
实际上,我自己会使用List<T>
;那么你可以这样做(虽然这不是使用List<T>
)的理由:
this.strings = new List<string>(strings);
答案 2 :(得分:1)
我认为应该尽可能避免倾斜。如果类将输入存储为具体类“Collection”(这意味着此类与“Collection”一起使用,那么我认为仅接受“Collection”类型的输入而不是接口对应的输入更自然。< / p>
这将转发(如果需要)的责任转移回了消费者,如果他做了贬低,他应该知道他在做什么。
另一方面,我会说接受输入作为接口比具体类更好,因为它允许更容易地提供模拟对象的灵活性。但是,这将要求类的内部依赖于接口而不是具体类(因此在示例中,成员变量将是IEnumerable而不是Collection)。
我同意yapiskan Marc的解决方案实际上通过创建输入的副本来改变使用方式,因此责任发生了变化:
之前:在消费者和此类之间始终共享输入。因此,对消费者和本类之间“共享”的输入
之后:在调用构造函数之后,此类对输入的理解与使用者分离。
答案 3 :(得分:0)
如果您存储的是Collection,那么我更喜欢将ICollection作为输入。
答案 4 :(得分:0)
这可能都是因为没有暴露太多的实现。理想情况下,如果您正在设计公共API,那么您应该只暴露最低限度的实现。如果你返回一个完整的List接口,那么公共API的用户将有很多方法以你可能没有想要的方式搞乱你的类的内部。
---- ----编辑
答案 5 :(得分:0)
为什么不接受IEnumerable<String>
类型的参数并将其投射到检索?
public ClassA
{
private IEnumberable<String> strings;
public Collection<String> StringCollection {
get { return (Collection<String>) strings; }
}
public ClassA(IEnumerable<String> strings)
{
this.strings = strings;
}
}
答案 6 :(得分:0)
我同意Paige的意见。
我同意你应该传递IEnumerable作为输入(这样你支持任何可枚举的集合)。
但是你在上面使用StringCollection属性所做的事情对我来说没有意义 - 你是堕落的,这是行不通的。
-Matt