【问题标题】:Protect lookup collections and items from editing保护查找集合和项目不被编辑
【发布时间】:2012-10-31 08:22:11
【问题描述】:

我根本不希望这些内容是可编辑的。对于 Collections,使用 ReadOnlyCollection 似乎非常清楚(尽管我不知道这是否是始终从 Collection 创建新的 ReadOnlyCollection 的好方法(成本高吗?))。

public static class Lookups
{
    private static Collection<MyBusinessObject> businessObjects;
    // [...]

    public static ReadOnlyCollection<MyBusinessObjects> BusinessObjects
    {
        get
        {
            return new ReadOnlyCollection<MyBusinessObject>(businessObjects);
        }
    }
    // [...]
}

但更重要的是:我如何处理集合中的项目?我希望这个测试通过任何想法?

    [TestMethod]
    public void Items_Should_Not_Be_Editable()
    {
        var businessObject = Lookups.BusinessObjects.First();

        businessObject.Id = 1337;

        Assert.AreNotEqual(1337, Lookups.BusinessObjects.First().Id);
    }

【问题讨论】:

    标签: c# collections readonly readonly-collection


    【解决方案1】:

    使用ReadonlyCollection 时,您不必每次都创建一个新实例。另一种方法是公开一个 IEnumerable,因为它也是只读的。 Readonlycollection 提供了更强的保护,可以看到here

    ReadOnlyCollection 泛型类的实例总是 只读。只读集合只是一个集合 防止修改集合的包装器;因此,如果 对基础集合进行更改,只读 收藏反映了这些变化。请参阅收藏以获取可修改的 此类的版本。

    [Test]
    public void TestNameTest()
    {
        var names = new List<string>() {"Johan", "Tkrause"};
        var readOnlyCollection = new ReadOnlyCollection<string>(names);
        names.Add("Lars");
        Assert.AreEqual(3,readOnlyCollection.Count);
    }
    

    在你的情况下:

    private List<IMyBusinessObjectType> _businessObjects= new List<IMyBusinessObjectType>();
    private ReadOnlyCollection<IMyBusinessObjectType> _readOnlybusinessObjects;
    public ReadOnlyCollection<IMyBusinessObjectType> BusinessObjects
    {
        get
        {
            if(_readOnlybusinessObjects==null)
                _readOnlybusinessObjects=new ReadOnlyCollection<IMyBusinessObjectType>(_businessObjects);
            return _readOnlybusinessObjects;
        }
    }
    
    public interface IMyBusinessObjectType
    {
        string Name { get; }
    }
    
    public class MyBusinessObjectType : IMyBusinessObjectType
    {
        public string Name { get; set; }
    }
    

    至于业务对象,它们可以有私有的 setter 或按照 Lars 的建议实现只读接口。

    【讨论】:

    • 但这意味着我需要第二块“私有静态”来包装“正常”集合,对吗?属性引用私有 ReadOnlyCollections,私有 ReadOnlyCollections 引用私有集合,并针对私有集合进行更新。
    • 更新了我的代码^^ 没有看到它是静态的。至于 readonlycollection 它是一个普通集合的包装器,使它只读,所以你是正确的。
    • 最后一件事:我更喜欢私有 setter 解决方案,但谁阻止我执行“new Something()”?这也会覆盖整个对象,而这在接口上是不可能的。你是否同意我的观点?嗯……纠正我。如果我有 ISomething,我仍然可以执行“ISomething x = new Something();” - 这会覆盖原始对象吗?
    • 但是你仍然可以做 IBusinessObject obj = new BusinessObject();您可以将 BusinessObject() 的 ctor 设为内部并获得一些控制,但我想这可能会与反序列化混淆。在这方面,私人二传手也可能是一个问题。界面路径不错。
    • 但是我可以用 IBusinessObject obj = new BusinessObject(); 覆盖对象正如你所说。如何获取底层接口?如何更改代码以返回 ReadOnlyCollection
    【解决方案2】:

    您应该从接口继承 MyBusinessObject 并将其公开。

    internal class MyBusinessObject : IMyBusinessObject {
        public string Id { get; set; }
    }
    
    public interface IMyBusinessObject {
        public string Id { get; }
    }
    

    然后在集合MyCollection中暴露这个接口。

    也许对集合做同样的事情,不要暴露添加、删除等方法。

    【讨论】:

      猜你喜欢
      • 2011-01-09
      • 2016-02-20
      • 2020-06-16
      • 2014-07-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-20
      • 2016-10-01
      相关资源
      最近更新 更多