0

I don´t want anything of these to be editable at all. For the Collections it seems crystal clear to use ReadOnlyCollection (though I don´t know if it´s a good way of always creating a new ReadOnlyCollection from the Collection (is it costly?)).

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

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

But more important: What do I do with items inside the collections? I want this test to pass any ideas?

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

        businessObject.Id = 1337;

        Assert.AreNotEqual(1337, Lookups.BusinessObjects.First().Id);
    }
timmkrause
  • 3,367
  • 4
  • 32
  • 59

2 Answers2

2

You should inherit MyBusinessObject from an interface and expose that.

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

public interface IMyBusinessObject {
    public string Id { get; }
}

And then expose this interface in the collection MyCollection.

Maybe do the same for the collection and dont expose the add, remove, etc methods.

2

When using ReadonlyCollection you don't have to create a new instance every time. An alternative is to expose an IEnumerable as it is read only too. Readonlycollection offers stronger protection as can be seen here.

An instance of the ReadOnlyCollection generic class is always read-only. A collection that is read-only is simply a collection with a wrapper that prevents modifying the collection; therefore, if changes are made to the underlying collection, the read-only collection reflects those changes. See Collection for a modifiable version of this class.

[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);
}

In your case:

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; }
}

As for the business objects they could have private setters or implement a read-only interface as suggested by Lars.

Community
  • 1
  • 1
Johan Larsson
  • 17,112
  • 9
  • 74
  • 88
  • But this would mean that I need a second block of "private statics" wrapping the "normal" collections right? The properties reference the private ReadOnlyCollections and the private ReadOnlyCollections reference the private Collections and updates are made against the private Collections. – timmkrause Oct 31 '12 at 08:53
  • Updated my code^^ did not see it was static. As for the readonlycollection it is a wrapper over a normal collection making it read only so you are correct. – Johan Larsson Oct 31 '12 at 08:57
  • Last thing: I would have preferred the private setter solution but who prevents me from doing a "new Something()"? That would overwrite the complete object too and that´s not possible with the interface. Do you agree with me? Mh... correct me. If I have ISomething, I could still do "ISomething x = new Something();" - will this overwrite the original object? – timmkrause Oct 31 '12 at 09:29
  • But you can still do IBusinessObject obj = new BusinessObject(); You could make the ctor of BusinessObject() internal and gain some control, but i guess that can mess with deserialization. Private setter might be a problem too in that regard. The interface path is nice. – Johan Larsson Oct 31 '12 at 09:42
  • But I could overwrite the object with IBusinessObject obj = new BusinessObject(); as you stated. How do I get the underlying interface? How do I have to change the code to return ReadOnlyCollection? – timmkrause Oct 31 '12 at 09:45
  • updated answer^^, keep the question open for a while. Maybe there is a better way to make the businessobject read only. – Johan Larsson Oct 31 '12 at 09:59