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.

AustinWBryan
  • 3,249
  • 3
  • 24
  • 42
  • 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? – Sebastian Hofmann May 20 '18 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 – salah-1 May 20 '18 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. – Mark Benningfield May 20 '18 at 19:25
  • @SebastianHofmann The method in question is only 11 lines – AustinWBryan May 20 '18 at 19:26
  • @Salah-1 What do you mean by "spit out"? And yes they are related enough. – AustinWBryan May 20 '18 at 19:27
  • @MarkBenningfield Right, but they'd still clutter the main file, and still show up in the auto-complete when I'm editing the class. The partial class idea is interesting though, I'll look into that. – AustinWBryan May 20 '18 at 19:28
  • 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. – Ben Voigt May 20 '18 at 19:31

4 Answers4

6

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.

InBetween
  • 32,319
  • 3
  • 50
  • 90
1

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.

xanatos
  • 109,618
  • 12
  • 197
  • 280
  • 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 May 20 '18 at 19:42
  • 1
    @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. – xanatos May 20 '18 at 19:46
  • I see, that's a clever rule of thumb – AustinWBryan May 20 '18 at 19:48
  • 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. – Ferazhu Oct 10 '22 at 12:50
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.

Paulo Morgado
  • 14,111
  • 3
  • 31
  • 59
-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();
}
Hossein Golshani
  • 1,847
  • 5
  • 16
  • 27
  • 3
    This has no advantages over the version shown in the question, and has the disadvantage of being even longer. – Ben Voigt May 20 '18 at 19:28
  • 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. – AustinWBryan May 20 '18 at 19:29
  • 1
    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](https://stackoverflow.com/questions/40943117/local-function-vs-lambda-c-sharp-7-0) – AustinWBryan May 20 '18 at 19:32
  • you right! I misunderstood the question. I didn't know about local functions in C# 7.0 But now I figured out. – Hossein Golshani May 22 '18 at 00:03
  • I thought perhaps you want a way to implement this behavior. – Hossein Golshani May 22 '18 at 00:10