3

Imagine I have this code:

public void Foo()
{
    // Do bar work
    // Do baz work
    // Do foobar work
}

And I realize I can (and should because it was doing more than one thing) refactor it into:

public void Foo()
{
    bar();
    baz();
    foobar();
}

private void bar()    { /* do bar work */ }
private void baz()    { /* do baz work */ }
private void foobar() { /* do foobar work */ }

But then I realize I will never use these functions outside of Foo(), so those functions are just cluttering the main page and the auto-complete. I could get away with this:

public void Foo()
{
    bar();
    baz();
    foobar();

    void bar()    { /* do bar work */ }
    void baz()    { /* do baz work */ }
    void foobar() { /* do foobar work */ }
}

Which would make things neater and less clutter, but all I've really done now is made the method even longer instead of shorter.

7
  • 2
    It can help you to increase readability and maintainability, but this depends on the methods. Are they containing lots of code or are they just a few lines? Commented May 20, 2018 at 19:23
  • I guess it comes down to readability. How much code does bar(), baz() and foobar() spit out if left on main function. Also, are they related enough to be on the main Commented May 20, 2018 at 19:24
  • 1
    If code organization is the only rub, just stick them in a partial class file by themselves. In addition, you can name private helper methods such that they don't jump right to the top of auto-complete. Commented May 20, 2018 at 19:25
  • @SebastianHofmann The method in question is only 11 lines Commented May 20, 2018 at 19:26
  • 1
    Your local function version seems just fine, it keeps things to the minimal necessary scope while still putting (I guess) useful names to the blocks of code. Commented May 20, 2018 at 19:31

4 Answers 4

8

Which would make things neater and less clutter, but all I've really done now is made the method even longer instead of shorter.

No, you haven’t. You are basically saying something similar to not being any difference between a class with one method that does a whole lot of stuff and a class that does the same job but with multiple shorter and easier to mantain methods.

Your local functions are just like methods, the fact that they are contained within another method doesn’t preclude that the whole is much easier to maintain; functionality is encapsulated in clearly defined scopes.

Sign up to request clarification or add additional context in comments.

Comments

2

I do love the idea of @Mark Benningfield of using partial files (it is what I do when my classes are too much big and there are one or two uber-methods)

My only problem with local functions is that they could capture variables, and it isn't always clear if the are doing it or not. So by "promoting" a "real" method to "local" you are enlarging the visibility it has.

4 Comments

Right, but sometimes the capturing of variables is the behavior I want. I do like local functions being able to use the parameters or local variables of the parent function directly without having to pass them as arguments.
@AustinWBryan There is no problem in capturing variables... Just I prefer that local functions do use this feature, other functions clearly don't. So I use this (capture/no capture) as the dividing line. But it is a line drawn in the sand.
I see, that's a clever rule of thumb
I think the capture thing is actually what you want, so you call the functions without parameters. Especially if the code is a long function where some variables have to persist from top to down.
1

Local functions provide advantages over anonymous functions because anonymous functions can only be invoke via delegates which, besides the memory allocation for the delegate, is a costlier invocation.

Local functions can be recursive without the trickery needed by delegates:

int f(int i) => i >= 1 ? i * f(i - 1) : 1;

Func<int,int> d = null;
d = (int i) => i >= 1 ? i * d(i - 1) : 1;

Like anonymous delegates, local functions, unlike top level methods, can capture local variables. And because thy are local, they can't be invoked by other functions.

Comments

-1

Use anonymous functions:

public void Foo()
{
    Action bar = delegate () { /* do bar work */ };
    Action baz = delegate () { /* do baz work */ };
    Action foobar = delegate () { /* do foobar work */ };

    bar();
    baz();
    foobar();
}

or lambda expression syntax:

public void Foo()
{
    Action bar = () => { /* do bar work */ };
    Action baz = () => { /* do baz work */ };
    Action foobar = () => { /* do foobar work */ };

    bar();
    baz();
    foobar();
}

5 Comments

This has no advantages over the version shown in the question, and has the disadvantage of being even longer.
That's effectively the same thing, except for the fact that I have to declare the anonymous functions ontop of the code. I like having the local functions underneath everything, including the return statements. I find it easier to read.
Also, there is a performance cost in using delegates because it has to allocate memory to create the delagate, but if I don't plan on passing that delegate to something else (which I don't) then that's wasted memory. Local functions don't have to allocate any memory for themselves, and they have nicer syntax. Check this out for their differences
you right! I misunderstood the question. I didn't know about local functions in C# 7.0 But now I figured out.
I thought perhaps you want a way to implement this behavior.

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.