views:

437

answers:

3

We have some stuff that may be exported into various formats. Currently we have these formats represented by an enum like this:

[Flags]
public enum ExportFormat
{
    None = 0x0,
    Csv = 0x1,
    Tsv = 0x2,
    Excel = 0x4,
    All = Excel | Csv | Tsv
}

Problem is that these must be enumerated and they also need a translation or description in the ui. Currently I solved this by creating two extension methods. They work, but I don't really like them or the solution at all... they feel kind of smelly. Problem is I don't really know how I could do this better. Does anyone have any good alternatives? These are the two methods:

    public static IEnumerable<ExportFormat> Formats(this ExportFormat exportFormats)
    {
        foreach (ExportFormat e in Enum.GetValues(typeof (ExportFormat)))
        {
            if (e == ExportFormat.None || e == ExportFormat.All)
                continue;

            if ((exportFormats & e) == e)
                yield return e;
        }
    }

    public static string Describe(this ExportFormat e)
    {
        var r = new List<string>();

        if ((e & ExportFormat.Csv) == ExportFormat.Csv)
            r.Add("Comma Separated Values");

        if ((e & ExportFormat.Tsv) == ExportFormat.Tsv)
            r.Add("Tab Separated Values");

        if ((e & ExportFormat.Excel) == ExportFormat.Excel)
            r.Add("Microsoft Excel 2007");

        return r.Join(", ");
    }

Maybe this is the way to do this, but I have a feeling there must be better ways to do it. If not that would be ok too, just curious to what others think :)

+1  A: 

The only other way comes to my mind is the usage of the System.Attribute class.

public class FormatDescription : Attribute
{
 public string Description { get; private set; }

 public FormatDescription(string description)
 {
  Description = description;
 }
}

And then use Reflection with in your Describe function. The only benefit of this method would be to have definition and the description at one place.

bassfriend
You might want to cache the lookups at runtime as they will not change and it would be costly to use reflection for repeated calls to Describe.
adrianbanks
This would be difficult to localize though, wouldn't it? Since as far as I know you can't really look up resource strings etc. when using attributes..
Svish
+3  A: 

You could use the Formats method inside Describe to avoid doing all the bit operations at multiple places, like this:

private static Dictionary<ExportFormat, string> FormatDescriptions =
    new Dictionary<ExportFormat,string>()
{
    { ExportFormat.Csv, "Comma Separated Values" },
    { ExportFormat.Tsv, "Tab Separated Values" },
    { ExportFormat.Excel, "Microsoft Excel 2007" },            
};

public static string Describe(this ExportFormat e)
{
    var formats = e.Formats();
    var descriptions = formats.Select(fmt => FormatDescriptions[fmt]);

    return string.Join(", ", descriptions.ToArray());
}

This way, it is easy to incorporate the string descriptions from an external source or localization, as hinted above.

Timbo
Smart :)
Svish
A: 

Dupe: http://stackoverflow.com/questions/796607/how-do-i-override-tostring-in-c-enums/796675#796675

You could write an TypeConverter that reads specified attributes to look them up in your resources. Thus you would get multi-language support for display names without much hastle.

Look into the TypeConverter's ConvertFrom/ConvertTo methods, and use reflection to read attributes on your enum fields.

Addition:

Scroll down in the linked post for a implementation of a TypeConverter that does part of what is required for full support.

This would support an application where you have several languages at the same time, not only code name -> english name.

Remember that this is only the display name, never the stored value. You should always store the code name, or the integer value, to support users with different locales using the same data.

Simon Svensson
Nice catch on the related question (dupe, I don't know), but I tend to agree with the higer rated answers to that question. If you make a custom TypeConverter, then you effectively change how that enum gets represented as a string, potentially effecting things like serialization, right? I do like the GetDescription and NicenessComboBoxItem ideas.
Paul Hooper