2

I am working on an API in C#. I am trying to think about the simplest way to expose my API for consumers of it. In particular, I have a class in my exposed data model that has a dictionary property. I'm trying to decide if the dictionary property should use strings as keys or an enum that I define as keys.

My concern with using strings as keys is that then the burden lies in the documentation to provide every possible string key value and the consumers end up working with string literals which could result in typos or duplication.

My concern with enums is that if we ever need to change the list of possible dictionary keys, this could be a breaking change for the API.

I'm leaning toward the enum, but my colleagues feel that a string would be best. Does anyone out there have any thoughts or advice on this?

  • 2
    Use an enum, but when adding new keys, always add them at the end of the existing ones. And never change or delete one after you released it. This makes sure the API does not break. – Doc Brown Jun 6 '16 at 19:25
  • 1
    if (key set is known && chance of needing to modify key set is low) ? enum : string; – Zymus Jun 6 '16 at 21:49
7

How is the API exposed? Through an ordinary .NET interface, or through REST or similar?

  • In the first case, enums are a good choice if you have a limited amount of accepted values. You can check valid values with Enum.IsDefined, you can have inline XML documentation explaining each value, and typo errors are checked by the compiler (and are caught even earlier with a capable IDE).

    Make sure everybody uses the values in a form MyEnum.SomeValue, and not in a form of underlying integers. If somebody uses integers, the risk is that when changing the order of the values within the enum or adding the values in the middle of it or removing values will change the match between some values and the underlying numbers.

    Also note the importance of Enum.IsDefined. The following code, and especially the last line, is perfectly valid, and will compile and run without errors. Guess what will be the console output?

    enum Color
    {
        Red = 1,
        Green = 2,
        Blue = 3,
    }
    
    void Demo(Color color)
    {
        Console.WriteLine(color.ToString());
    }
    
    Demo((Color)4);
    
  • In the second case, the values from enum will usually appear as numbers, and remembering what means 14 or 17 in a given context is not particularly exciting. So here, stick with meaningful string values.

    Make sure you use an explicit map instead of a simple ToString. Renaming a value within the enum is a simple refactoring task and shouldn't break the code. If the string value matches the actual value name within the enum, the code will break in a subtle way which wouldn't be easy to debug.

    See also: Is this a Best Practice with Enum in C# and the comments by MK87.

  • The API in this case is a .Net interface. Consumers simply reference our dll either from an installer or nuget package. I generally like enums because they are somewhat self-documenting as you suggest in your answer. – Brian Jun 6 '16 at 15:31
1

If the object represented by your Dictionary has a finite, well-defined set of values that can be identified ahead of time (which seems like it must be true, otherwise you wouldn't be able to use an enum for the key), then why are you using a Dictionary at all? Create a data class or struct that has one field for each possible value. This has several benefits:

  • Better IDE integration: consumers will see see automatic completion of the field names in their IDE without having to specifically identify which enum they want to pull the data out of. Documentation will be easier to find than it would be for an enum.
  • Better type safety: unless all of your data items have exactly the same type, you can specify exact types for the fields and make sure that the data is correctly used at compile time
  • Better efficiency: an object has virtually-zero-time lookup and modification cost. It uses the minimum amount of memory that could be possibly stored for the data that you need to keep. It interacts with the GC in much cleaner fashion.

Honestly, I fail to see the advantage of using a Dictionary here at all.

  • I understand where you are coming from here. The reason we chose to use a dictionary is because there can be a lot of variability in which keys have values for any given object. That means that if this were a class it could have several properties that would not have values at any given time. Now, that could be overcome with inheritance, but it seems a little overkill for our use case. – Brian Jun 6 '16 at 15:44
  • @Brian what exactly is the problem with a spats class? Maybe a little reflection can help mitigate the problem? – Esben Skov Pedersen Jun 6 '16 at 21:19
  • @EsbenSkovPedersen I'm not sure I know what you mean by "spats" class? – Brian Jun 6 '16 at 21:45
  • Sorry meant to type sparse – Esben Skov Pedersen Jun 7 '16 at 12:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.