In a previous blog post, I demonstrated how Java’ enums that
contain one or more values/objects can be emulated with C#. One thing
bothered me, though: the switch
statement and how inconvenient it
was to determine the proper type. Worst of all, it was not type-safe.
In my simple example, it was easy because I was using strings. Imagine
your fake-enum does not contain a string to quickly identify the
instance.
Well, there is a prettier workaround – and it involves an actual
enum
. I was thinking about how the same could be done in C++ and in
C++, you can have type conversion operators. Then I searched if such a
feature also exists in C#, and sure enough, it does.
The new class looks as follows.
public sealed class CharacterReplacementCode
{
public enum Type
{
Colon, Pound, QuestionMark
}
public static readonly CharacterReplacementCode Colon = new CharacterReplacementCode(Type.Colon, ":", "&58;");
// Other readonly's
// IEnumerable<CharacterReplacementCode> Values
public static implicit operator CharacterReplacementCode.Type(CharacterReplacementCode replacementCode)
=> replacementCode.EnumType;
public Type EnumType { get; private set; }
// Other properties
CharacterReplacementCode(Type type, string character, string code)
=> (EnumType, Character, Replacement) = (type, character, code);
// ToString
}
I have added a Type
enum, and I have also added another property
EnumType
to hold that value. It is set when the readonly CharacterReplacementCode
instances are defined. The important piece
is the implicit operator
with which a class instance can be
converted to the respective enum
value. It is the value that is set
in the constructor.
The switch
statement now looks almost like one would expect from
switching an enum.
foreach (var code in CharacterReplacementCode.Values) {
switch ((CharacterReplacementCode.Type)code) {
case CharacterReplacementCode.Type.Colon:
Console.WriteLine("COLON: " + code);
break;
case CharacterReplacementCode.Type.Pound:
Console.WriteLine("POUND: " + code);
break;
case CharacterReplacementCode.Type.QuestionMark:
Console.WriteLine("QUESTION: " + code);
break;
}
}
The only exception is casting from CharacterReplacementCode
to
CharacterReplacementCode.Type
, but other than that, it works like a
regular enum-switch. If you prefer, you can also define the enum
outside of the class.
You can find the complete example on Github.
I hope this helps. Thank you for reading.
Epilogue
One more small note on the use-case: the sample I have shown here is simplistic, and using two strings may not show the full potential. Imagine writing a configurable system that initializes factories based on string values in a config file. I like to use enum literals to represent the configuration values and then associate further objects, like a specific factory or a service, with the enum. You are not restricted to using strings, as I have mentioned in my first blog post. An enum must not only be a "dumb" value, but it can also contain meaningful data.
Here is some pseudo-code:
public enum AudioConverterType {
MP3(new Mp3Converter(), new Mp3TagWriter()),
AAC(new AacConverter(), new AacTagWriter());
private AudioConverterInterface converter;
private TagWriterInterface tagWriter;
// Constructor
// Getter
}
Once you have determined the correct enum type from a configuration value, you immediately gain access to the conversion and tag-writer service. Another, maybe more traditional, approach would be the use of factories.
More pseudo-code.
public class AudioManagementFactory {
public AudioConverterInterface getConverter(AudioConverterType enumType) {
// Switch on enumType and return the correct converter
}
public TagWriterInterface getTagWriter(AudioConverterType enumType) {
// Switch on enumType and return the correct tag-writer
}
}
Use whatever floats your boat 🙂
[…] have written a follow-up that improves on the following solution using a type conversion operator […]
LikeLike