Best Practise: Returning private List<> as a Property

P

Paul

Hi,

I feel I'm going around circles on this one and would appreciate some other
points of view.

From a design / encapsulation point of view, what's the best practise for
returning a private List<> as a property.

Consider the example below, the class "ListTest" contains a private "List<>"
called "strings" - it also provides a public method to add to that list,
this method could contain all sorts of validation / modification of the
string to be added (encapsulation). However by then exposing the private
List<> as a public property you give the end user of your class the ability
to add to your List<> as show below.

I understand why the above happens, I'm just trying to think what the best
course of action is if you always want your user to use the function to add
to your list, whilst retaining a property to access the list? List<>
doesn't contain a clone method - you could create this I know, but then the
amount of processing that involves implies it should be a method rather than
a parameter (parameters shouldn't really consider processor intensive code).

Like I say, I feel I'm going around in circles on this one, even to the
point of wondering if it actually matters.

Regards,

- Paul.
====================================
using System;
using System.Collections.Generic;
using System.Text;

class Program
{
static void Main(string[] args)
{
ListTest listTest = new ListTest();
listTest.AddString("Test 1"); // << Add the string the correct way.
Console.WriteLine(listTest.Strings.Count);
listTest.Strings.Add("Test 2"); // << by-pass the AddString()
function.
Console.WriteLine(listTest.Strings.Count);
}
}

class ListTest
{
private List<string> strings = null;

public void AddString(string stringToAdd)
{
if (strings == null)
strings = new List<string>();
strings.Add(stringToAdd);
}
public List<string> Strings { get { return this.strings; } }
}
====================================
Output is:
1
2
 
G

Giulio Petrucci

Hi Paul,

Paul ha scritto:
[cut]

I think I haven't properly got what you need...
Antyway - taking a look to your code - the best way should be you to
create your *own* collection (implementing ICollection<T>) and
customizing the "Add" method.

HTH,
Giulio
 
D

Dustin Campbell

I feel I'm going around circles on this one and would appreciate some
other points of view.

From a design / encapsulation point of view, what's the best practise
for returning a private List<> as a property.

Consider the example below, the class "ListTest" contains a private
"List<>" called "strings" - it also provides a public method to add to
that list, this method could contain all sorts of validation /
modification of the string to be added (encapsulation). However by
then exposing the private List<> as a public property you give the end
user of your class the ability to add to your List<> as show below.

I understand why the above happens, I'm just trying to think what the
best course of action is if you always want your user to use the
function to add to your list, whilst retaining a property to access
the list? List<> doesn't contain a clone method - you could create
this I know, but then the amount of processing that involves implies
it should be a method rather than a parameter (parameters shouldn't
really consider processor intensive code).

Like I say, I feel I'm going around in circles on this one, even to
the point of wondering if it actually matters.

====================================
using System;
using System.Collections.Generic;
using System.Text;
class Program
{
static void Main(string[] args)
{
ListTest listTest = new ListTest();
listTest.AddString("Test 1"); // << Add the string the correct
way.
Console.WriteLine(listTest.Strings.Count);
listTest.Strings.Add("Test 2"); // << by-pass the AddString()
function.
Console.WriteLine(listTest.Strings.Count);
}
}
class ListTest
{
private List<string> strings = null;
public void AddString(string stringToAdd)
{
if (strings == null)
strings = new List<string>();
strings.Add(stringToAdd);
}
public List<string> Strings { get { return this.strings; } }
}
====================================
Output is:
1
2

List<> should be used internally and never exposed. Once you expose it, you're
design is locked into using it. If you just need a way to iterate over the
List<> from outside, you might consider making ListTest implement IEnumerable<string>
like this:

class ListTest: IEnumerable<string>
{
List<string> strings = new List<string>();

public IEnumerator<string> GetEnumerator()
{
return strings.GetEnumerator();
}
}

Or, if you want to return the contents, you could expose a read-only indexer:

class ListTest
{
List<string> strings = new List<string>();

public string this[int index] { get { return strings[index]; } }
}

Another option is to return a ReadOnlyCollection<string>:

class ListTest
{
List<string> strings = new List<string>();

public ReadOnlyCollection<string> Strings { get { return strings.AsReadOnly();
} }
}

You might even consider doing all three. But, directly exposing the inner
bits of your class is a bad idea for lots of reasons.

Best Regards,
Dustin Campbell
Developer Express Inc.
 
G

Giulio Petrucci

Dustin Campbell ha scritto:
List<> should be used internally and never exposed. Once you expose it,
you're design is locked into using it. If you just need a way to iterate
over the List<> from outside, you might consider making ListTest
implement IEnumerable<string> like this:

....and if you need to "manipulate" object from outside
(add/remove/clear) you should use a ICollection<T>.

My 2 cents,
Giulio - Italia
 
C

Christof Nordiek

Hi,

you could use the AsReadOnly method of the List<T> class. It returns a
writeprotected wrapper around your list.

your Strings property would look like this:

public ReadOnlyCollection<string> Strings { get { return
strings.AsReadOnly() } }

The returned List will still have the Add method soice it implements IList<>
and List<>, but they will cause exceptions.
Not very nice, but atleast the caller can't change your internals.

Christof
 
J

JS

...and if you need to "manipulate" object from outside
(add/remove/clear) you should use a ICollection<T>.

I'm just curious. Why is returning an ICollection<T> preferrable to
returning an IList<T> ?
 
B

Bruce Wood

Paul said:
Hi,

I feel I'm going around circles on this one and would appreciate some other
points of view.

From a design / encapsulation point of view, what's the best practise for
returning a private List<> as a property.

Consider the example below, the class "ListTest" contains a private "List<>"
called "strings" - it also provides a public method to add to that list,
this method could contain all sorts of validation / modification of the
string to be added (encapsulation). However by then exposing the private
List<> as a public property you give the end user of your class the ability
to add to your List<> as show below.

I understand why the above happens, I'm just trying to think what the best
course of action is if you always want your user to use the function to add
to your list, whilst retaining a property to access the list? List<>
doesn't contain a clone method - you could create this I know, but then the
amount of processing that involves implies it should be a method rather than
a parameter (parameters shouldn't really consider processor intensive code).

Like I say, I feel I'm going around in circles on this one, even to the
point of wondering if it actually matters.

Regards,

- Paul.
====================================
using System;
using System.Collections.Generic;
using System.Text;

class Program
{
static void Main(string[] args)
{
ListTest listTest = new ListTest();
listTest.AddString("Test 1"); // << Add the string the correct way.
Console.WriteLine(listTest.Strings.Count);
listTest.Strings.Add("Test 2"); // << by-pass the AddString()
function.
Console.WriteLine(listTest.Strings.Count);
}
}

class ListTest
{
private List<string> strings = null;

public void AddString(string stringToAdd)
{
if (strings == null)
strings = new List<string>();
strings.Add(stringToAdd);
}
public List<string> Strings { get { return this.strings; } }
}
====================================
Output is:
1
2

You might choose to use a custom list type. Take a look at how
ListViewItemCollection works.
 
G

Giulio Petrucci

Hi JS,

JS ha scritto:
I'm just curious. Why is returning an ICollection<T> preferrable to
returning an IList<T> ?

It's just a more "restricted" interface.

Kind regards,
Giulio
 
P

Paul Hadfield

Christof,

Thanks for the advice, it's a very clean solution - nice to know that I
wasn't going mad thinking there was a better way of doing things.

Also, you have to cast the returned "ReadOnlyCollection" property as a
"ICollection<T>" to get the Add value because it's an Explicit Interface
implementation (see below) - if you just use the property without the cast
you can't even see / use the Add method.

((ICollection<String>)listTest.Strings).Add("Test 2"); // << This will throw
the exception.

Thanks again,

- Paul.

Christof Nordiek said:
Hi,

you could use the AsReadOnly method of the List<T> class. It returns a
writeprotected wrapper around your list.

your Strings property would look like this:

public ReadOnlyCollection<string> Strings { get { return
strings.AsReadOnly() } }

The returned List will still have the Add method soice it implements
IList<> and List<>, but they will cause exceptions.
Not very nice, but atleast the caller can't change your internals.

Christof

Paul said:
Hi,

I feel I'm going around circles on this one and would appreciate some
other points of view.

From a design / encapsulation point of view, what's the best practise for
returning a private List<> as a property.

Consider the example below, the class "ListTest" contains a private
"List<>" called "strings" - it also provides a public method to add to
that list, this method could contain all sorts of validation /
modification of the string to be added (encapsulation). However by then
exposing the private List<> as a public property you give the end user of
your class the ability to add to your List<> as show below.

I understand why the above happens, I'm just trying to think what the
best course of action is if you always want your user to use the function
to add to your list, whilst retaining a property to access the list?
List<> doesn't contain a clone method - you could create this I know, but
then the amount of processing that involves implies it should be a method
rather than a parameter (parameters shouldn't really consider processor
intensive code).

Like I say, I feel I'm going around in circles on this one, even to the
point of wondering if it actually matters.

Regards,

- Paul.
====================================
using System;
using System.Collections.Generic;
using System.Text;

class Program
{
static void Main(string[] args)
{
ListTest listTest = new ListTest();
listTest.AddString("Test 1"); // << Add the string the correct
way.
Console.WriteLine(listTest.Strings.Count);
listTest.Strings.Add("Test 2"); // << by-pass the AddString()
function.
Console.WriteLine(listTest.Strings.Count);
}
}

class ListTest
{
private List<string> strings = null;

public void AddString(string stringToAdd)
{
if (strings == null)
strings = new List<string>();
strings.Add(stringToAdd);
}
public List<string> Strings { get { return this.strings; } }
}
====================================
Output is:
1
2
 
P

Paul Hadfield

Thanks Dustin,

That's really helpful - I've gone with the ReadOnlyCollection option as it
does exactly what I wanted - sometimes I do want to return the whole
collection, not just iterate over it or return specific elements.

Regards,

- Paul.


Dustin Campbell said:
I feel I'm going around circles on this one and would appreciate some
other points of view.

From a design / encapsulation point of view, what's the best practise
for returning a private List<> as a property.

Consider the example below, the class "ListTest" contains a private
"List<>" called "strings" - it also provides a public method to add to
that list, this method could contain all sorts of validation /
modification of the string to be added (encapsulation). However by
then exposing the private List<> as a public property you give the end
user of your class the ability to add to your List<> as show below.

I understand why the above happens, I'm just trying to think what the
best course of action is if you always want your user to use the
function to add to your list, whilst retaining a property to access
the list? List<> doesn't contain a clone method - you could create
this I know, but then the amount of processing that involves implies
it should be a method rather than a parameter (parameters shouldn't
really consider processor intensive code).

Like I say, I feel I'm going around in circles on this one, even to
the point of wondering if it actually matters.

====================================
using System;
using System.Collections.Generic;
using System.Text;
class Program
{
static void Main(string[] args)
{
ListTest listTest = new ListTest();
listTest.AddString("Test 1"); // << Add the string the correct
way.
Console.WriteLine(listTest.Strings.Count);
listTest.Strings.Add("Test 2"); // << by-pass the AddString()
function.
Console.WriteLine(listTest.Strings.Count);
}
}
class ListTest
{
private List<string> strings = null;
public void AddString(string stringToAdd)
{
if (strings == null)
strings = new List<string>();
strings.Add(stringToAdd);
}
public List<string> Strings { get { return this.strings; } }
}
====================================
Output is:
1
2

List<> should be used internally and never exposed. Once you expose it,
you're design is locked into using it. If you just need a way to iterate
over the List<> from outside, you might consider making ListTest implement
IEnumerable<string> like this:

class ListTest: IEnumerable<string>
{
List<string> strings = new List<string>();

public IEnumerator<string> GetEnumerator()
{
return strings.GetEnumerator();
}
}

Or, if you want to return the contents, you could expose a read-only
indexer:

class ListTest
{
List<string> strings = new List<string>();

public string this[int index] { get { return strings[index]; } }
}

Another option is to return a ReadOnlyCollection<string>:

class ListTest
{
List<string> strings = new List<string>();

public ReadOnlyCollection<string> Strings { get { return
strings.AsReadOnly(); } }
}

You might even consider doing all three. But, directly exposing the inner
bits of your class is a bad idea for lots of reasons.

Best Regards,
Dustin Campbell
Developer Express Inc.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top