Creating a custom type converter part 3: Types to string
How to use a TypeConverter to provide editing of immutable structs that are properties of containing objects via a PropertyGrid.
The last two articles (here and here) described creating a custom type converter for converting units of measurement.
However, what happens when you want to display or convert to/from alternative representations? For example, consider the enum below.
Apart from the fact such an enum more than likely doesn't match any coding standards you use, what happens when you want to include percentages in the mix? Not many languages are going to let you use % as a symbol name!
So we rewrite the enum to make more sense, in which case you might have this:
Great! Except... your users want to see cm, px, % etc. Now what?
Well, you could create a function which takes a unit, and manually checks the values and returns an appropriate value, for example:
While this would certainly work, it means you have to duplicate this code for every enum you wish to have alternate descriptions for. Not to mention, should you add a new member to the enum, you have to remember to update this function. More than likely, you also want a sister version of this function which accepts the string version, and returns the enum value.
A better way would be to tag each enum member with an appropriate description, then you can use reflection to scan your enum members and perform automatic to and from conversions.
In this example, I'm going to use the DescriptionAttribute
from the System.ComponentModel
namespace, although depending
on what you're trying to do, a custom attribute may be better -
that's not exactly what this attribute was intended for!
First, decorate your enum with the attribute.
Next add a couple of functions that will perform the conversion of your enum to and from a string. With this in place you can add new members, and, as long as you add your attribute to them, the functions will automatically handle the new values.
I choose to make the version that accepts the enum member as an input parameter an extension method, that way I can call it like this:
However, as the sister method accepts a string parameter, it doesn't make sense to make this an extension, unless you want it to appear on every single string variable you declare! So I just revert back to the usual static calling convention.
While there's nothing wrong with the above methods, they could still be improved upon. As it stands now, the methods are fixed to a specific enum, so we can change them to use generics instead, then they'll work for all enums.
Using reflection does have an overhead. If you expect to be
calling these methods a lot, you may wish to extend them yet
further in order to support caching the results in a dictionary
or other mechanism of your choice. That way, the first time a
new member is requested you perform the reflection lookup, and
thereafter just read the cache. I haven't done any benchmarking,
but it's probably safe to say a dictionary lookup (remember to
use TryGetValue
!) is going to be a lot faster than a
reflection scan.
An example showing how the custom type converter from the previous two articles updated to use the above technique is available from the link below.
Like what you're reading? Perhaps you like to buy us a coffee?
# Ofer