2

Is there a way to use a string resource with a switch statement? After trying to obtain a string resource programmatically, an error is returned.

Error

'resourceLoader' is variable but is used like a type

C#

public class PageConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        var resourceLoader = Windows.ApplicationModel.Resources.ResourceLoader.GetForCurrentView();

        Type page = null;
        switch (value as string)
        {
            case resourceLoader.GetString("SteveJohnson/Text"):
                page = typeof(FirstPage);
                break;
            case resourceLoader.GetString("PeteDavidson/Text"):
                page = typeof(SecondPage);
                break;
            case resourceLoader.GetString("OneDrive/Text"):
                page = typeof(FistPage);
                break;
            case resourceLoader.GetString("Twitter/Text"):
                page = typeof(SecondPage);
                break;
            default:
                break;
        }

        return page;
    }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        throw new NotImplementedException();
    }
}
8
  • 3
    No, they must be compile-time constants. Looks like you could use a Dictionary<string, Type> instead. Commented Aug 17, 2020 at 15:41
  • 1
    I think you've got a typo; fistPage to firstPage ? Commented Aug 17, 2020 at 16:18
  • 2
    @CodeCaster: "they must be compile-time constants" -- this used to be the case, but no longer. It's unfortunate that the author of this question did not spend time researching before posting, but it is true that existing Q&A on SO about the limitations of switch have largely been invalidated by recent features added to C#, i.e. pattern-matching, which take away the blanket prohibition against non-constant expressions for case statements. Commented Aug 17, 2020 at 20:09
  • @PeterDuniho I did do research before asking this question but didn’t find the relevant sources. d219 gave an answer but the code returns a warning. Commented Aug 17, 2020 at 21:16
  • 2
    @CodeCaster: yeah, I don't dispute your complaints about that answer. But it does seem to literally accomplish what was asked. And honestly, without having more context from the OP, it's not clear whether a dictionary-based approach would really be more readable. That said, my only point was to correct the notion that in today's C#, case statements are required to use only constant expressions. Commented Aug 18, 2020 at 5:09

2 Answers 2

2

Are you looking for pattern matching? It's only something I've found recently (it's a C# 7 feature which I came across in this link) and what you're doing is a little different from the use case I had but I've just run a quick test with pseudo code (calling a method of another class which takes and returns a string from the switch statement) which seemed to work. For what you're doing I think you'd have something like this:

switch (value)
{
    case string _ when (resourceLoader.GetString("SteveJohnson/Text") == value as string):
                    page = typeof(FistPage);
                    break;
    case string _ when (resourceLoader.GetString("PeteDavidson/Text") == value as string):
                    page = typeof(SecondPage);
                    break;
Sign up to request clarification or add additional context in comments.

5 Comments

A warning is returned: Possible unintended reference comparison; to get a value comparison, cast the right hand side type to 'string'
Hmm, potentially you need to ToString() the value you are using for the switch? (test code I wrote is on other laptop but have made an edit above, see if that works, if not I'll have another look tomorrow - it's assuming the ToString of the object is what you need to do the comparison on of course).
After trying ToString() the warning is still there
OK fired up the other laptop as couldn't see why there'd been a problem - I skim read your message above and thought it was an error, now I realise it's a warning (as you said) have corrected by moving your original as string into each case statement; that gets rid of the warning :)
Also replaced the variable name I had before with the discard _ as you don't need to do anything with that return value.
1

I think you need to take a step back and look at why you want a switch statement: probably to have a readable block of code. You could easily do the same with a couple of if()s:

var resourceLoader = Windows.ApplicationModel.Resources.ResourceLoader.GetForCurrentView();

Type page = null;
if (value == resourceLoader.GetString("SteveJohnson/Text"))
    page = typeof(FirstPage);
else if (value == resourceLoader.GetString("PeteDavidson/Text"))
    page = typeof(SecondPage);
else if (value == resourceLoader.GetString("OneDrive/Text"))
    page = typeof(FistPage);
else if (value == resourceLoader.GetString("Twitter/Text"))
    page = typeof(SecondPage);      

return page;

Now you could rewrite this using pattern when clauses to shoehorn it into a switch, but I don't think that's the appropriate construct here, as it doesn't really increase readability. You could opt for a Dictionary with options instead:

var pageTypes = new Dictionary<string, Type>
{
    { resourceLoader.GetString("SteveJohnson/Text"), typeof(FirstPage) },
    { resourceLoader.GetString("PeteDavidson/Text"), typeof(SecondPage) },
    { resourceLoader.GetString("OneDrive/Text"), typeof(FirstPage) },
    { resourceLoader.GetString("Twitter/Text"), typeof(SecondPage) },
};

// Defaults to `null` when not mached
pageTypes.TryGetValue((string)value, out Type page);
return page;

You could even cache the resource lookups by initializing this dictionary once, for example in the constructor of the containing class.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.