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?

有帮助吗?

解决方案

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.

其他提示

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.

许可以下: CC-BY-SA归因
scroll top