通常将内部数据结构公开为业务类的属性。但是当我们必须暴露类似数组的结构(如List< Rule>规则)时,我们可能会遇到错误使用的问题(如选项1中所示)。
它建议将这种数据结构的克隆暴露为属性,这样内部结构就不会受到干扰。
对于这个,有没有人有一个很好的解决方案?
public class Rule
{
}
public class RulesManager
{
List<Rule> rules = new List<Rule>();
public List<Rule> Rules
{
get { return rules; }
set { rules = value; }
}
public void Add(Rule r)
{
rules.Add(r);
// Do something else after add;
}
public void Delete(Rule r)
{
rules.Remove(r);
// Do something else after delete;
}
}
public class CallingCode
{
public static void Main()
{
RulesManager r = new RulesManager();
// Option 1
r.Rules.Add(new Rule());
// Option 2
r.Add(new Rule());
}
}
答案 0 :(得分:2)
您可以使用Clone
返回rules
的只读版本,而不是返回rules.AsReadOnly()
。
public IList<Rule> Rules
{
get { return rules.AsReadOnly(); }
// set { rules = value; -- should not be allowed to set if read only!
}
请注意IList
。
答案 1 :(得分:0)
您可以返回IEnumerable,而不是返回List。 IEnumerable允许用户遍历集合,但它不允许用户轻松修改它。
或者你可以返回一个arryay而不是一个列表。这将创建用户无法轻易修改的列表副本。
最后,您应该知道用户也可能修改集合的内容。这可能是您想要的,但您可能还想要退回商品的副本。
答案 2 :(得分:0)
我认为将IList公开为属性是很常见的,但我更喜欢只公开显式的Add / Delete函数。如果你正在开发更多的框架,你也可以考虑在你的类中实现一个集合接口(例如IList)。
而不是:
public List<Rule> Rules
{
get { return rules; }
set { rules = value; }
}
我更喜欢在类上实现IEnumerable<T>
和索引器,以便我可以控制列表中发生的事情。
答案 3 :(得分:0)
查看ReadOnlyCollection和AsReadOnly()列表方法。
答案 4 :(得分:0)
一个基本的解决方法是使用List<T>.AsReadOnly()
方法,它将围绕ReadOnlyCollection包装列表以阻止任何“写入”访问。当然,你必须将setter设为私有,否则就没有意义......
另一种选择是实现您自己的IList,它会在“写入”访问的情况下提醒您,并允许您执行业务逻辑。