4

How can I convert below foreach statement in corresponding linq with possible null handling:

foreach (var val in userData.ManagedUsers.Values)
        {
            if (val.UserId == userId)
            {
                foreach (var role in val.Roles)
                {
                    switch (role.ToLower())
                    {
                        case "underwriter1":
                            return "1";
                        case "underwriter2":
                            return "2";
                        case "underwriter3":
                            return "3";
                    }
                }
            }
        }
nectar
  • 9,525
  • 36
  • 78
  • 100

2 Answers2

6

You could use this:

string result = userData.ManagedUsers.Values
    .Where(u => u.UserId == userId)
    .SelectMany(u => u.Roles)
    .Select(r => {
        if(String.Equals(r, "underwriter1", StringComparison.InvariantCultureIgnoreCase))
            return "1";
        else if(String.Equals(r, "underwriter2", StringComparison.InvariantCultureIgnoreCase))
            return "2";
        else if(String.Equals(r, "underwriter3", StringComparison.InvariantCultureIgnoreCase))
            return "3";
        else return null; 
    }).First(r => r != null);

I don't use a switch here because you need to use ToLower to compare case-insensitively. You don't pass the turkey test then. Therefore i'm using String.Equals with InvariantCultureIgnoreCase which is also more efficient and handles the case that Role is null.

By the way, this seems to be even better if i understand your logic correctly:

 string result = userData.ManagedUsers.Values
     .Where(u => u.UserId == userId)
     .SelectMany(u => u.Roles)
     .Select(r => r != null && r.StartsWith("underwriter") ? r.Substring("underwriter".Length) : null)
     .First();
Community
  • 1
  • 1
Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
  • Have you tried this? (Has anyone who upvoted, or OP who accepted?) – Rawling Jan 27 '15 at 08:46
  • @Rawling: it was difficult to test without the classes or sample data. – Tim Schmelter Jan 27 '15 at 08:50
  • It's not hard to test the "interesting" step with `new string[0]`. – Rawling Jan 27 '15 at 08:53
  • @Rawling: you're right, i've tested it. The lambda expression needs to return something which was not the case without the `else`. I've fixed it with an exception. I've also added another more concise approach. – Tim Schmelter Jan 27 '15 at 09:01
  • 1
    With the exception there, you only ever check the first role. – Rawling Jan 27 '15 at 09:02
  • @Rawling: i came to the conclusion that your version is the best way ;) – Tim Schmelter Jan 27 '15 at 09:06
  • Heh, we converge eventually. There are probably further improvements we could both make if we both look at "what *should* this code be doing" rather than "how can I replace these loops" but to be honest I can't be bothered. – Rawling Jan 27 '15 at 09:08
1

Since C# 8.0 the following should work:

string result = userData.ManagedUsers.Values
.Where(u => u.UserId == userId)
.SelectMany(u => u.Roles)
.Select(r => 
    r.ToLower() switch
    {
       "underwriter1" => "1",
       "underwriter2" => "2",
       "underwriter3" => "3"
    }).First(r => r != null);
Peanut
  • 3,753
  • 3
  • 31
  • 45