2

I'm looking for an automated way of sorting a large block of case statments.

switch (id) {
    case RadGridStringId.ClearSortingMenuItem: return "Annuler les tris";
    case RadGridStringId.ConditionalFormattingMenuItem: return "Formatage conditionnel";
    case RadGridStringId.GroupByThisColumnMenuItem: return "Grouper par cette colonne";
    case RadGridStringId.UngroupThisColumn: return "Dégrouper cette colonne";
    case RadGridStringId.ColumnChooserMenuItem: return "Masqueur de colonnes";
    case RadGridStringId.HideMenuItem: return "Masquer cette colonne";

    case RadGridStringId.ConditionalFormattingBtnApply: return "Appliquer";
    case RadGridStringId.ColumnChooserFormCaption: return "Masqueur de colonnes";
    case RadGridStringId.ColumnChooserFormMessage: return "Ajouter ici une colonne\npour la faire disparaitre\ntemporairement de la vue";
    case RadGridStringId.GroupingPanelDefaultMessage: return "Ajouter ici une colonne pour faire un regroupement par cette colonne";
    case RadGridStringId.GroupingPanelHeader: return "Groupe par";
    case RadGridStringId.ClearValueMenuItem: return "Effacer la Valeur";
    case RadGridStringId.ConditionalFormattingContains: return "Contient [Valeur1]";
    case RadGridStringId.ConditionalFormattingDoesNotContain: return "Ne contient pas [Valeur1]";
    case RadGridStringId.ConditionalFormattingEndsWith: return "Finit par [Valeur1]";
    case RadGridStringId.ConditionalFormattingEqualsTo: return "Est égal à [Valeur1]";
    case RadGridStringId.ConditionalFormattingIsBetween: return "Est compris entre [Valeur1] et [Valeur2]";
    case RadGridStringId.ConditionalFormattingIsGreaterThan: return "Est supérieur à [Valeur1]";
    case RadGridStringId.ConditionalFormattingIsGreaterThanOrEqual: return "Est supérieur ou égal à [Valeur1]";
    case RadGridStringId.ConditionalFormattingIsLessThan: return "Est inférieur à [Valeur1]";
    case RadGridStringId.ConditionalFormattingIsLessThanOrEqual: return "Est inférieur ou égal à [Valeur1]";
    case RadGridStringId.ConditionalFormattingIsNotBetween: return "Non compris entre [Valeur1] et [Valeur2]";
    case RadGridStringId.ConditionalFormattingIsNotEqualTo: return "Est différent de [Valeur1]";
    case RadGridStringId.ConditionalFormattingStartsWith: return "Commence par [Valeur1]";
    case RadGridStringId.ConditionalFormattingRuleAppliesOn: return "La règle s'applique au champ:";
    case RadGridStringId.ConditionalFormattingChooseOne: return "[Choisir un type]";
    case RadGridStringId.NoDataText: return "Pas de données à afficher";

    default:
        return base.GetLocalizedString(id);
}

Does anyone know a tool, add-on or extension for doing that in Visual Studio 2013/2015?

Update on 2015-11-12

Additional infos: This is only a design-time problem for me. I'm using Telerik controls. Unfortunately this controls doesn't provide any out-of-the-box translation of their controls. They only provide a translation mechanism.

I can find different files for different languages on the net (e. g. this here). But they are incompleteted and the order of the case statements in this files are different.

To see differences in these files a sorted switch statement would make life much easier :)

PS: An additional nice to have feature were a way to extend the switch of currently missing/unused enum values.

Regards, Daniel

Community
  • 1
  • 1
Daniel C.
  • 569
  • 2
  • 7
  • 19
  • 1
    No, do it in MS Excel or something. – rory.ap Nov 10 '15 at 14:13
  • 16
    Use a `Dictionary` instead of this mess – Tim Schmelter Nov 10 '15 at 14:16
  • 1
    In the example you show, you are probably better off using an array or dictionary of values and forget the code overhead. Just index the array using the enum (converted to an int) or dictionary using the value as the key. – iCollect.it Ltd Nov 10 '15 at 14:16
  • @TimSchmelter I may be missing something, does a `Dictionary` really make it any neater? – Lukazoid Nov 10 '15 at 15:23
  • 1
    @Lukazoid: the initialization part is not much better although you can use a collection initializer. But a dictionary is a collection, so you can write much more readable and maintainable code than with a `switch`. This question ("how to sort `switch`") suggests that this is a [XY-Problem](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). – Tim Schmelter Nov 10 '15 at 15:29
  • 1
    @TimSchmelter He only wants the case statement sorted at design-time and not the entries at runtime, so I don't believe it is an XY-Problem. If he wanted all the enums and their associated values sorted, I would agree with you. The problem is, the asker has a `switch` statement which they want sorted, they haven't actually offered a solution. – Lukazoid Nov 10 '15 at 17:36
  • 1
    @TimSchmelter At least a switch statement gives you compile time safety over accidently specifying the same enum value twice, I personally prefer the use of the switch for this reason. – Lukazoid Nov 10 '15 at 17:39
  • I provided some more info in my question. – Daniel C. Nov 12 '15 at 08:48
  • @TimSchmelter Like Lukazoid, I also do not see how a `Dictionary<,>`, even with collection initializer syntax, would be less "messy". And how do you sort the pairs `.. { x, y }, ...` in the initializer more easily than you sort the `case` sections in the `switch`? In my opinion, the `switch` statements exists exactly because it is *less* messy than having your own look-up object. And Lukazoid's latest comment about compile-time checking for duplicate keys is important too! – Jeppe Stig Nielsen Nov 12 '15 at 09:33

1 Answers1

4

As mentioned in the comments, you could simply copy the lines to Excel, sort the rows alphabetically, and paste them back in the code. However, this large switch statement will be a pain to maintain later on. You should consider another approach, such as using a Dictionary.

In the following code, a dictionary with all the texts are created

private static Dictionary<RadGridStringId, string> texts;

private static void InitializeTexts()
{
    texts = new Dictionary<RadGridStringId, string>();
    texts[RadGridStringId.ClearSortingMenuItem] = "Annuler les tris";
    texts[RadGridStringId.ConditionalFormattingMenuItem] = "Formatage conditionnel";
    texts[RadGridStringId.GroupByThisColumnMenuItem] = "Grouper par cette colonne";
    texts[RadGridStringId.UngroupThisColumn] = "Dégrouper cette colonne";
    texts[RadGridStringId.ColumnChooserMenuItem] = "Masqueur de colonnes";
    texts[RadGridStringId.HideMenuItem] = "Masquer cette colonne";
    texts[RadGridStringId.ConditionalFormattingBtnApply] = "Appliquer";
    texts[RadGridStringId.ColumnChooserFormCaption] = "Masqueur de colonnes";
    texts[RadGridStringId.ColumnChooserFormMessage] =
        "Ajouter ici une colonne\npour la faire disparaitre\ntemporairement de la vue";
    texts[RadGridStringId.GroupingPanelDefaultMessage] =
        "Ajouter ici une colonne pour faire un regroupement par cette colonne";
    texts[RadGridStringId.GroupingPanelHeader] = "Groupe par";
    texts[RadGridStringId.ClearValueMenuItem] = "Effacer la Valeur";
    texts[RadGridStringId.ConditionalFormattingContains] = "Contient [Valeur1]";
    texts[RadGridStringId.ConditionalFormattingDoesNotContain] = "Ne contient pas [Valeur1]";
    texts[RadGridStringId.ConditionalFormattingEndsWith] = "Finit par [Valeur1]";
    texts[RadGridStringId.ConditionalFormattingEqualsTo] = "Est égal à [Valeur1]";
    texts[RadGridStringId.ConditionalFormattingIsBetween] = "Est compris entre [Valeur1] et [Valeur2]";
    texts[RadGridStringId.ConditionalFormattingIsGreaterThan] = "Est supérieur à [Valeur1]";
    texts[RadGridStringId.ConditionalFormattingIsGreaterThanOrEqual] = "Est supérieur ou égal à [Valeur1]";
    texts[RadGridStringId.ConditionalFormattingIsLessThan] = "Est inférieur à [Valeur1]";
    texts[RadGridStringId.ConditionalFormattingIsLessThanOrEqual] = "Est inférieur ou égal à [Valeur1]";
    texts[RadGridStringId.ConditionalFormattingIsNotBetween] = "Non compris entre [Valeur1] et [Valeur2]";
    texts[RadGridStringId.ConditionalFormattingIsNotEqualTo] = "Est différent de [Valeur1]";
    texts[RadGridStringId.ConditionalFormattingStartsWith] = "Commence par [Valeur1]";
    texts[RadGridStringId.ConditionalFormattingRuleAppliesOn] = "La règle s'applique au champ:";
    texts[RadGridStringId.ConditionalFormattingChooseOne] = "[Choisir un type]";
    texts[RadGridStringId.NoDataText] = "Pas de données à afficher";
}

A simple getter that initializes the dictionary if it wasn't already, and returns the string.

private static string getText(RadGridStringId id)
{
    if (texts == null)
    {
        InitializeTexts();
    }
    if (texts.ContainsKey(id))
    {
        return texts[id];
    }
    else
    {
        return string.Empty; // or base.GetLocalizedString(id);
    }
}

Then you simply use the method:

private static void Main(string[] args)
{
    RadGridStringId id = RadGridStringId.GroupingPanelHeader;
    string test = getText(id);
    Console.WriteLine(test); //prints: "Groupe par"
}
Lars Kristensen
  • 1,410
  • 19
  • 29
  • 1
    I agree a dictionary is much better, but you do have a one-time race condition on construction. Unlikely, but possibly a problem later. You could alleviate that through static initialization and/or an initializer list on the static member, which is what I'd advocate for. – Kevin Anderson Nov 10 '15 at 14:59
  • @KevinAnderson Initialization of the dictionary should be improved - this was just an example to show that it would be easier to maintain a dictionary, than a large, sorted switch statement. – Lars Kristensen Nov 10 '15 at 15:06
  • Out of interest, what makes a switch statement harder to maintain than a dictionary? – Lukazoid Nov 10 '15 at 15:24
  • @Lukazoid It might boil down to personal preference, but in OPs case there wouldn't be a need to sort the different cases in the switch statement (and keep them sorted, if new cases are added later on). – Lars Kristensen Nov 10 '15 at 15:29
  • @Lukazoid If several different cases would return the same string, then the switch approach might be better, but in OPs case there are 1:1 relations between the Enum values and the corresponding strings, I would say a dictionary is better suited for the purpose. – Lars Kristensen Nov 10 '15 at 15:41
  • 1
    @LarsKristensen I still don't understand how an unsorted dictionary is any better than an unsorted switch statement. With your example, it's too easy to have duplicate indexers for the same key with different values where only the last takes effect. – Lukazoid Nov 10 '15 at 17:34
  • 1
    I provided some more info in my question. – Daniel C. Nov 12 '15 at 08:48
  • This does *not* answer the question "how can I sort the `case` sections?". The syntax you propose is *not* robust towards accidentally including the same key twice. That will *overwrite* the old key/value pair! You could use another syntax (`Add` calls, or collection initializer), but it would only be checked at run-time if you had duplicates. With the `switch` statement multiple `case` labels with the same value are illegal already at compile-time. Your "solution" raises the question: "How can I sort a lot of statements of the type `texts[RadGridStringId.Foo] = "Bar";`? – Jeppe Stig Nielsen Nov 12 '15 at 09:28
  • @DanielC. If you want to stick with your switch approach, then I would recommend simply sorting the lines using Excel. I can't think of a way to automate this process. However, it sounds like what you really need, is a resource file with translated texts. Take a look here: http://stackoverflow.com/a/1142840/717088 – Lars Kristensen Nov 12 '15 at 09:35
  • In your `getText` method you make the classical mistake of doing the look-up twice. First with `texts.ContainsKey(id)`, and then with `texts[id]`. You must use `TryGetValue`. Like this: `string text; if (texts.TryGetValue(id, out text) { return text; } return base.GetLocalizedString(id);` – Jeppe Stig Nielsen Nov 12 '15 at 09:38
  • @JeppeStigNielsen You're right, the initilization of the dictionary should have been done using the Add method to avoid duplicates, and the fetching of the text should be done without double-checking the key. Though I did mention that the lines can be sorted using Excel, I'm not sure if this process can be automated. Also, it seems that OP really needs to use a Resource file instead of this aproach. – Lars Kristensen Nov 12 '15 at 09:43
  • @LarsKristensen You are right, in this special scenario a resource file is a much better solution. But this doesn't answer my question.Using Excel is one way to do this, but this is only really useful with one line case "blocks". If we have more lines in case block, I think Excel can not to this. – Daniel C. Nov 14 '15 at 17:43