How to make List's Add method protected, while exposing List with get property?
Solution 1
As others have said, you are looking for the .AsReadOnly()
extension method.
However, you should store a reference to the collection instead of creating it during each property access:
private readonly List<SomeOtherClass> _items;
public WhatClass()
{
_items = new List<SomeOtherClass>();
this.Items = _items.AsReadOnly();
}
public ReadOnlyCollection<SomeOtherClass> Items { get; private set; }
This is to ensure that x.Items == x.Items
holds true, which could otherwise be very unexpected for API consumers.
Exposing ReadOnlyCollection<>
communicates your intent of a read-only collection to consumers. Changes to _items
will be reflected in Items
.
Solution 2
You're looking for the ReadOnlyCollection<T>
class, which is a read-only wrapper around an IList<T>
.
Since the ReadOnlyCollection<T>
will reflect changes in the underlying list, you don't need to create a new instance every time.
For example:
public class WhatClass {
public WhatClass() {
_SomeOtherClassItems = new List<SomeOtherClass>();
SomeOtherClassItems = _SomeOtherClassItems.AsReadOnly();
}
List<SomeOtherClass> _SomeOtherClassItems;
public ReadOnlyCollection<SomeOtherClass> SomeOtherClassItems { get; private set; }
}
Solution 3
Use List<T>.AsReadOnly
:
public ReadOnlyCollection<SomeOtherClass> SomeOtherClassItems
{
get
{
return _SomeOtherClassItems.AsReadOnly();
}
}
This will return a ReadOnlyCollection, which will throw an exception if a client calls Add through the interface. In addition, the ReadOnlyCollection type does not expose a public Add method.
Solution 4
How about using AsReadOnly()
? - MSDN Documentation
Solution 5
List<T>
implements IReadOnlyList<T>
since .NET Framework 4.5, so an internal list can be exposed as IReadOnlyList<T>
instead for that purpose.
public class WhatClass
{
List<SomeOtherClass> _SomeOtherClassItems;
public IReadOnlyList<SomeOtherClass> SomeOtherClassItems => _SomeOtherClassItems;
}
Related videos on Youtube
Nikola Malešević
A software engineer with a strong focus on industrial automation, embedded systems and 2D/3D graphics programming. Also note that I will beat you in ping-pong and you will regret challenging me.
Updated on December 25, 2021Comments
-
Nikola Malešević over 2 years
I have a class named WhatClass that has List field in it. I need to be able to read-only this field, so I used a get property to expose it to other objects.
public class WhatClass { List<SomeOtherClass> _SomeOtherClassItems; public List<SomeOtherClass> SomeOtherClassItems { get { return _SomeOtherClassItems; } } }
However it turns out that any object can call
WhatClass.SomeOtherClassItems.Add(item);
How can I prevent this?
-
SLaks almost 14 yearsDon't make a new instance each time.
-
Dave Markle almost 14 yearsYou might want to elaborate for the masses what happens when you add to _items and how you deal with that...
-
ChaosPandion almost 14 years@Dave - The docs state that changes will be reflected in the wrapper.
-
Quartermeister almost 14 years@SLaks: I see your point, but that's a micro-optimization and I believe it's easier to read this way. ReadOnlyCollection is small and the GC is good at dealing with small short-lived objects, and you're just as likely to wind up using more memory by adding a field and a ReadOnlyCollection object that you don't need for every one of your classes.
-
SLaks almost 14 yearsAllocating objects in a property getter is a bad idea. People generally assume that a accessing a property getter is nothing more than a memory read, and will therefore access the property many times in large nested loops.
-
Quartermeister almost 14 years@SLaks: Never mind, I see the argument about reference equality in Bryan's answer. I hadn't considered that.
-
Nikola Malešević almost 14 yearsBryan, thank you very much for this answer, although I do not need a readonly keyword here.
-
Nikola Malešević almost 14 yearsThank you for your answer. You mentioned ReadOnlyCollection<T> class, but didn't include it in the code, but I've figured it out. Thank you once again.
-
Bryan Watts almost 14 years@Witchunter: you aren't assigning
_items
after the constructor; thereadonly
keyword communicates that intent: msdn.microsoft.com/en-us/library/acdd6hb7.aspx. If you plan on assigning another value to_items
afterWhatClass
is constructed, you will also need to reassign theItems
property.