-2

I'm trying to return some fields (e.g. cellPhone, mainAddress, cityStateZip, serverSetup) from below function based on input, and I have implemented an interesting switch statement, but clearly I'm returning a string in all cases.

public static string JsonToObjects(bool Enumerate, string jsonInputFile)
{
    string inputFile = Path.GetFileName(jsonInputFile); // Return File Name + Extension
    var lines = GetLines(File.ReadAllText(jsonInputFile));
    var groups = lines.GroupByProximity(0.12);
    var lookup = groups.ToLookup(g => g.First().Text, g => g.Skip(1).Select(line => line.Text));
    var serverSetup = lookup["Server Setup"]
        .First().SkipWhile(s => s.ToString().ToUpper() != "V").Skip(1).FirstOrDefault();

    switch (Enumerate)
    {
        case true:
            Log("\nEnumerating JSON items...\n");
            
            var cellPhone = lookup["Cell Phone"].First().FirstOrDefault();
            var mainAddress = lookup["Main Address"].First().FirstOrDefault();
            var cityStateZip = lookup["City / State / Zip"].First().FirstOrDefault();

            Log(cellPhone);
            Log(mainAddress);
            Log(cityStateZip);
            Log(serverSetup);

            Log("\n");

            var pairs = lines.SkipWhile(l => l.Text != "Practice Name").Pairs();

            // Ingest the lines in pairs and setup the values to go out into the CSV.
            foreach (var pair in pairs)
            {
                Log($"{pair.Key}: {pair.Value}");
                return $"{pair.Key}: {pair.Value}";
            }

            break;
        case false:
            Log("Using Cho Package...");

            using (var p = new ChoJSONReader(jsonInputFile).WithJSONPath("$..readResults")) // "readResults": [
            {
                p.Where(r1 => r1.page == 1)
                .Select(r1 =>
                {
                    var lines = (dynamic[])r1.lines;
                    return new
                    {
                        FileName = inputFile,
                        Page = r1.page,
                        CellPhone = //lines[12].text,
                            fieldValue(lines, "Cell Phone"),
                        //cellPhone,
                        MainAddress = //lines[16].text,
                            fieldValue(lines, "Main Address"),
                        //mainAddress,
                        CityStateZip = //lines[18].text,
                            fieldValue(lines, "City / State / Zip"),
                        //cityStateZip,
                        ServerSetup = serverSetup
                    };
                }
                );
            }
            break;
        default:
            Log("Default case");
            return "Default case";
            break;
    }
}

Why then am I still getting an error:

"Not all code paths return a value"

halfer
  • 19,824
  • 17
  • 99
  • 186
Cataster
  • 3,081
  • 5
  • 32
  • 79
  • 2
    imagine `pairs` being empty - and the body of your foreach never being executed. also, you do ***not*** have a return in your `case false`. question answered? – Franz Gleichmann Apr 29 '21 at 06:00
  • 2
    the return is not in your `case false`, statement, but in the _lambda function inside your `.Select`_ so no, it does not. i recommend reading up on the basics of c#'s syntax. – Franz Gleichmann Apr 29 '21 at 06:06
  • 2
    You don't have a return statement in your `false` case. Simple as that. You need to return a string before it breaks. – Enigmativity Apr 29 '21 at 06:28
  • 1
    You need to think more about what you want to do when things don't work out. In the false case, what if there are no page==1 in your p? The return will never run. What then? *what should you return in that case*? In the true, what if there are no pairs? What is sensible to return if there are no pairs? Return that.. – Caius Jard Apr 29 '21 at 06:34
  • 1
    `one return in the section is enough` It is enough. But you don't have one. Yes, you have one in `p.Where(r1 => r1.page == 1) .Select(r1 => { var lines = (dynamic[])r1.lines; return new` but that isn't returning from the method. That is returning from the `Select` only. And that is putting aside the fact that you aren't _doing_ anything with the `Where` so you may as well remove all of that code anyway. Take a step back and explain what you want the function _to do_. – mjwills Apr 29 '21 at 06:40
  • @mjwills the main purpose is for the function to parse the JSON and return the fields (e.g. cellPhone, mainAddress, cityStateZip, serverSetup) so they can be used by another program (the goal is to load them into netsuite.) I suppose I can get rid of the ChoJSON section but I am only trying to debug this for learning purposes since im trying to improve my c# after many years not programming in it. – Cataster Apr 29 '21 at 06:50
  • It's not enough to have _some_ `return` statements. _Every possible code path_ must terminate with a `return` statement. And that's exactly what the error message is telling you. You need to fix the code so that _every possible code path_ has a `return` statement. See duplicate. As has already been explained several times, your `true` case might never execute the `foreach` body, so there's a possible code path without a `return`, and the `false` case doesn't even have a valid `return` _anywhere_ in the `case` statement itself. – Peter Duniho Apr 29 '21 at 07:41

1 Answers1

1

Either change every break in your switch so that it is a return (if you will vary what you return based on whether the true or the false case is applied) or put a return statement at the end of your method, after your switch is finished with

The compiler isn't kidding; it really can see paths through your code that don't end in a return. You can trace them too.. follow your true case.. it can reach break, exit the switch and then have no return statement before it hits the end of the method. You might be certain that pairs will definitely always have a value but the compiler doesn't have that same level of knowledge about the program as you and it doesn't trace back to try and find evidence that pairs will always have a value.. it just sees "return statement inside a loop which is a block that might not execute, means code might not hit that return statement"

In case you're under an illusion as to what default is for, in a switch.. it is used when no other case applies. It is not "something that runs every time, regardless of whether some other case applied or not" so it can't be used as a catch all to return something if other cases didn't

If you're certain that one of your returns in the switch will be hit you can return something useless at the end of the method or better, throw an exception with a meaningful message so that in 6 months when all these "None of the switch statements returned a value in JsonToObjects, the input values were..." start appearing in the logs you have a good pointer to what is going wrong and where. Do not make your error message "this should never be hit"

Caius Jard
  • 72,509
  • 5
  • 49
  • 80
  • hmm, when i changed breaks to return i got `Control cannot fall through from one case label case:false to another`. Also, actually in the `case:false` i tried returning one of the fields like `return CityStateZip` and yet it complained it complained `The name CityStateZip does not exist in the current context.` i tried returning it within the using and outside the using, to no avail. – Cataster Apr 29 '21 at 06:17
  • That sounds like you've removed a `break` and not supplied a `return` meaning the compiler now sees a path where your code reaches the start of a next case, which isn't allowed in c#. The second problem is it sounds like you've tried to return CityStateValue outside the scope in which it exists.It only exists inside the anonymous type generated inside the select. You can't just take a variable and drag it up 3 scopes (out of 3 levels of bracket nests) and paste it in.Go back to the form you had in the Q, and throw an exception at the end of the method instead.When the code errors, work out why – Caius Jard Apr 29 '21 at 06:28
  • `you can return something useless at the end of the method` it resolved the error in the `case:false` section when i returned something like `return "useless something"`. Great now I need to return the actual fields though. I tried returning within the select scope, outside it, yet none is working, keeps complaining that it doesnt exist in current context. I suppose, how do i return fields like this that are lambda'd? – Cataster Apr 29 '21 at 06:34
  • I mean i can honestly get rid of the second case since the first one is working just fine and call it a day, but im still curious to get the `case:false` working for learning purposes. – Cataster Apr 29 '21 at 06:38
  • Is that not what your code does, when it says `Select(return new...` ? You can have as many return as you like.. you don't have to *move* the return out of the select (weird as it is to do a select return), you just add another one. It means the compiler will be happy that it can hit a return no matter what – Caius Jard Apr 29 '21 at 06:38
  • For some reason it still complains about it not existing in the context. I am not even moving the `return new` – Cataster Apr 29 '21 at 06:40
  • Show the code (take a screenshot with snipping tool, press ctrl c, hit Edit on your question, paste, wait for it to upload, cut the imgur url out of the question body, cancel the edit and post the url into a comment here. – Caius Jard Apr 29 '21 at 06:41
  • here you go, tried diffreent scenarios: https://i.stack.imgur.com/4wpnu.png, https://i.stack.imgur.com/4xdwv.png, https://i.stack.imgur.com/0YxZT.png – Cataster Apr 29 '21 at 06:48
  • Yes, citystatezip doesn't exist in any of those places. It only exists inside the new anonymous object that will be returned within the select. You have to provide some other value; it doesn't make sense to try and return citystatezip from any of those other places because some of those those other places don't need to return a value and others don't have citystatezip as "a thing". The place that needs to return is "above default" and you get to that place if there isn't even any data available to form a citystatezip so you have to think of something else to return, like `return "no data"` – Caius Jard Apr 29 '21 at 07:01
  • Gotcha. and in the scenario with the first case statement, since i have to return multiple fields, is this the right way to do it? `return $"cellPhone, mainAddress, cityStateZip, serverSetup";` or do i have to return it as an array of strings? – Cataster Apr 29 '21 at 07:25
  • The method is declared to return a single string so if anything it looks like your first idea would work.. returning an array of strings from a method that is declared to return `string` is impossible. You can still accept and upvote any posted answers even if a question is closed, I think. Closing just means no new answers can be posted. https://meta.stackexchange.com/questions/91827/can-an-answer-of-a-closed-question-be-accepted – Caius Jard Apr 29 '21 at 07:56