Reputation: 35853
Say I have:
class foo
{
private List<T> bar;
public IEnumerable<T> GetBar();
}
where GetBar()
should return that very same List, without exposing internals (i.e. no other class should be able to remove elements from the internal list, reorder it etc.) and avoiding excessive copying. What is the standard way to do this?
Upvotes: 2
Views: 418
Reputation: 81247
A property which encapsulates part of an object's mutable state may, if the type is a mutable class, represent any of these:
If the type is read-only, but not guaranteed to be immutable, it may represent any of these:
While the type of the determined object may be used to distinguish the first set of three behaviors from the latter set, I know of no standard convention to indicate, in the absence of a suitable guaranteed-immutable return type, which of the behaviors within the appropriate set applies. Since there is no guaranteed-immutable implementation of IEnumerable<T>
that would seem applicable here, your best bet is probably to use Joe's code, but also document your behavior as #3. Unless you can think of some reason clients would benefit from #2, documenting your behavior as #3 will give you the most flexibility to change your implementation in future should that be necessary. For example, if thread-safe access ends up being necessary in the future, your class could implement an internal method which locks the collection long enough to copy it to an array and returns that array (possibly wrapped in ReadOnlyCollection<T>
, though it probably wouldn't matter) cast as IEnumerable<T>
. Such an approach wouldn't work if the property was supposed to represent a live view.
Upvotes: 0
Reputation: 124746
If you want to return an immutable list, return bar.AsReadOnly()
.
Typically the member that exposes this readonly wrapper would be of type IList<T>
. I would only downcast to IEnumerable<T>
if I wanted to indicate to the consumer that the implementation might use lazy enumeration.
Personally I'd make it a property, and return the same readonly wrapper on each invocation:
class Foo
{
private List<T> bar;
private IList<T> readonlyBar;
public Foo()
{
bar = ...;
readonlyBar = bar.AsReadOnly();
}
public IList<T> Bar
{
get { return readonlyBar; }
}
}
Upvotes: 8
Reputation: 38488
You can return an instance of ReadOnlyCollection from your method:
return new ReadOnlyCollection(items);
Upvotes: 7