I have a class which has two HashSet<String>
collections as private members. Other classes in my code would like to be able to iterate over those HashSets and read their contents. I don't want to write a standard getter because another class could still do something like myClass.getHashSet().Clear();
Is there any other way to expose the elements of my HashSets to iteration without exposing the reference to the HashSet itself? I'd love to be able to do this in a way that is compatible with for-each loops.
views:
246answers:
7Expose a IEnumerable<T>
property:
public IEnumerable<whatevertype> MyHashSet {
get {
return this.myHashSet;
}
}
Of course, the user of this code can cast that IEnumerable<T>
to a HashSet<T>
and edit elements, so to be on the safe side (while hurting performance), you can do:
public IEnumerable<whatevertype> MyHashSet {
get {
return this.myHashSet.ToArray();
}
}
or:
public IEnumerable<whatevertype> MyHashSet {
get {
foreach(var item in this.myHashSet) {
yield return item;
}
}
}
A more performant method of protection, but less convenient to the caller, is to return an IEnumerator<T>
:
public IEnumerator<whatevertype> GetMyHashSetEnumerator() {
return this.myHashSet.GetEnumerator();
}
Add a method/property like this to avoid exposing the actual container:
public IEnumerable EnumerateFirst()
{
foreach( var item in hashSet )
yield return item;
}
Make your getter expose the HashSet as IEnumerable.
private HashSet<string> _mine;
public IEnumerable<string> Yours
{
get { return _mine; }
}
If the generic type is mutable, then that can still be modified, but no items can be added or removed from your HashSet.
You may also provide a sequence like this:
public IEnumerable<string> GetHashSetOneValues()
{
foreach (string value in hashSetOne)
yield return value;
}
This method may then be called within a foreach loop:
foreach (string value in myObject.GetHashSetOneValues())
DoSomething(value);
You can also use the Select
method to create a wrapper than can't be cast back to HashSet<T>
:
public IEnumerable<int> Values
{
get { return _values.Select(value => value);
}
This avoids iterating over _values
twice, as you would with .ToArray()
, but keeps the implementation to a single clean line.
Assuming you're using .NET 3.5, one alternative to writing the yield code yourself is to call a LINQ method. For example:
public IEnumerable<string> HashSet
{
get { return privateMember.Select(x => x); }
}
or
public IEnumerable<string> HashSet
{
get { return privateMember.Skip(0); }
}
There are various LINQ operators which could be used like this - using Skip(0)
is probably the most efficient, as after the initial "skip 0 values" loop, it's probably just the foreach
/yield return
loop shown in the other answers. The Select
version will call the no-op projection delegate for each item yielded. The chances of this difference being significant are astronomically small, however - I suggest you go with whatever makes the code clearest to you.
You could Clone the HashSet
in conjunction with typing the property as `IEnumerable'
public IEnumerable<[private HashSet type]> HashClone
{
get { return new HashSet<[private HashSet type]>( _privateHashSetVar ); }
}
While this protects against nefarious methods being called against the HashSet itself, it does not protect against someone iterating over a HashSet of reference types and doing something on those types. The obvious downside is that it will eat up more memory. However, if the HashSets are small, it shouldn't matter.