views:

369

answers:

5

Its typical to expose internal data structures as properties to your business class. But when we have to expose array-like structures (like List<Rule> rules) we might encounter a problem of wrong usage (as in Option 1).

Its suggested to expose clone of such data structures as properties, so that internal structure does not get disturbed.

Does any one have a well-settled solution for this?

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());
    }
}
+2  A: 

Instead of returning a Clone, you can return a read-only versionof "rules" using rules.AsReadOnly().

public IList<Rule> Rules
{
  get { return rules.AsReadOnly(); }
// set { rules = value; -- should not be allowed to set if read only!
}

Note the IList.

danbystrom
But my definition will change from List<Rule> to ReadOnlyCollection<Rule>, rt?
nils_gate
Ever heard of type casting? :-) I'll clarify...
danbystrom
A: 

Instead of returning a List you can return an IEnumerable. The IEnumerable allows the user to iterate through the collection, but it doesn't allow the user to modify it easily.

Alternatively you could return an arryay instead of a list. This will create a copy of the list that the user cannot easily modify.

Finally you should be aware that the user might also modify the contents of the collection. This may be what you want, but you might also want to return copies of your items.

Rune Grimstad
A: 

I think it is quite common to expose the IList as a property, but I prefer to expose only explicit Add/Delete functions. You can also consider to implement one of the collection interfaces in your class (IList for instance), if you are developing something more of a framework.

Instead of:

public List<Rule> Rules
{
    get { return rules; }
    set { rules = value; }
}

I prefer to implement IEnumerable<T> and an indexer on the class, so that I have control over what happens to the list.

Grzenio
A: 

Check out the ReadOnlyCollection and the AsReadOnly() List method.

Sam
A: 

A basic workaround is to use List<T>.AsReadOnly() method, which will wrap the list around a ReadOnlyCollection to block any "write" access. Of course, you'd have to make the setter private, otherwise it would not make sense...

Another alternative would be to implement your own IList that would alert you in case of "write" access and allow you to perform your business logic.

ybo