Question

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.

Was it helpful?

Solution

Expose 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();
}

OTHER TIPS

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.

Add a method/property like this to avoid exposing the actual container:

public IEnumerable EnumerateFirst()
{
     foreach( var item in hashSet )
         yield return item;
}

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.

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);

This might be quite a bit too late to the party but the easiest way today would be to use Linq. Instead of writing

public IEnumerable<string> GetValues() 
{
    foreach(var elem in list)
        yield return elem; 
}

you can write

public IEnumerable<string> GetValues() => list;

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top