Reputation: 11549
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.
Upvotes: 2
Views: 1634
Reputation: 309
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;
Upvotes: 1
Reputation: 59503
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);
Upvotes: 0
Reputation: 1502226
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.
Upvotes: 6
Reputation: 45465
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.
Upvotes: 3
Reputation: 90042
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();
}
Upvotes: 3
Reputation: 28426
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.
Upvotes: -1
Reputation: 9474
Add a method/property like this to avoid exposing the actual container:
public IEnumerable EnumerateFirst()
{
foreach( var item in hashSet )
yield return item;
}
Upvotes: 3