3

Right now I have a const array of strings and loop through to check if a value exists. But I want a more efficient way to store my values. I know there's a hashset which I can use like so:

HashSet<string> tblNames = new HashSet<string> ();
tblNames.Add("a");
tblNames.Add("b");
tblNames.Add("c");

However, is it possible to make this a constant member of my class like this:

public const HashSet<string> tblNames = new HashSet<string>() { "value1", "value2" };
mjwills
  • 23,389
  • 6
  • 40
  • 63
DannyD
  • 2,732
  • 16
  • 51
  • 73
  • 3
    `But I want a more efficient way to store my values.` What do you mean by `more efficient`? – mjwills Apr 03 '19 at 01:37
  • 4
    I'd suggest using `static readonly` rather than `const`. Alas, since it is `public` other code will be able to add or remove items from the `HashSet`. – mjwills Apr 03 '19 at 01:40
  • 2
    To be fair, I don't think this is necessarily a duplicate of the `const` questions, as they don't address preventing the Set contents from being added/removed. – NPras Apr 03 '19 at 05:06
  • 1
    The OP probably wants an immutable `HashSet`. There is an [`ImmutableHashSet`](https://learn.microsoft.com/en-us/dotnet/api/system.collections.immutable.immutablehashset-1) class in the package [System.Collections.Immutable](https://www.nuget.org/packages/System.Collections.Immutable/). – Theodor Zoulias Sep 15 '19 at 05:09

1 Answers1

13

The best way to create a 'constant' Set is probably by exposing your HashSet as its IEnumerable interface, using the following:

public static readonly IEnumerable<string> fruits = new HashSet<string> { "Apples", "Oranges" };
  • public: everyone can access it.
  • static: there's only going to be one copy in memory, no matter how many instances of the parent class is created.
  • readonly: you can't re-assign it to a new value.
  • IEnumerable<>: you can only iterate through its contents, but not add/remove/modify.

To search, you can use LINQ to call Contains() on your IEnumerable, and it is smart enough to know it's backed by a HashSet and delegate the proper call to utilise the hashed nature of your set. (well, ok, it calls it via ICollection, but ends up in HashSet's overridden method anyway)

Debug.WriteLine(fruits.Contains("Apples")); // True
Debug.WriteLine(fruits.Contains("Berries")); // False

fruits = new HashSet<string>(); // FAIL! readonly fields can't be re-assigned
fruits.Add("Grapes"); // FAIL! IEnumerables don't have Add()
NPras
  • 3,135
  • 15
  • 29
  • I am curious why a const field can't be marked as static but a readonly value can – DannyD Apr 03 '19 at 18:38
  • 1
    From the C# language spec: [A constant or type declaration is implicitly a static member](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/static) – NPras Apr 04 '19 at 00:47
  • This is not constant it's readonly. Therefore useless when the expression must be constant. Would be more useful to investigate whether or not it is possible to create a constant hash table in C#. – Hugues Beauséjour Jun 30 '22 at 19:16
  • 1
    Just to clarify on this `and it is smart enough to know it's backed by a HashSet and delegate the proper call to utilise the hashed nature of your set. (well, ok, it calls it via ICollection, but ends up in HashSet's overridden method anyway)` IEnumerable and ICollection are simply interfaces. They do not define default implementations for `Contains()`. When you call `Contains()` it will directly call the hashset implementation. – JFord Jul 29 '22 at 21:24