68

Is it possible to declare a method within another method in C#?

For example like that:

void OuterMethod()
{
    int anything = 1;
    InnerMethod();     // call function
    void InnerMethod()
    {
        int PlitschPlatsch = 2;
    }
}
Non
  • 1,936
  • 2
  • 17
  • 24
  • Why do you want to do this? What problem are you trying to solve? What situation are you trying to model? – Cody Gray - on strike May 04 '11 at 13:43
  • 1
    @Cody Gray I've got a method with a lot of code, which I want to structure for better reading and understanding. Since this part of the Code is not needed by other methods, i thought of splitting the code inside of the Method. – Non May 04 '11 at 14:14
  • 6
    Yeah, and that's exactly why I asked. A lot of helpful people are talking about lambdas and `Func`s, but that's not really what you want here. If you think you need to refactor code out of an existing method, just create a new method in your `.cs` file, and make sure it's marked `private`. If you don't need to call it from anywhere else, then don't. No reason to overcomplicate things unnecessarily. – Cody Gray - on strike May 04 '11 at 14:16
  • possible duplicate of [how to create function inside another function in c#,is it possible?](http://stackoverflow.com/questions/2047200/how-to-create-function-inside-another-function-in-c-is-it-possible) – Ferruccio Jun 03 '15 at 15:40
  • 7
    Cody Gray: why must every structure have only 3 levels? (namespace, class, function) This is equal to having only 3 levels of folder depth, which will not be enough. This is decided by the user. Some functionality might be better placed not accessible for other functions of the same class, because they might be only called together or in a specific order. > 20 years of development and nobody thought of that. Instead we have lambda... – TheTrowser Dec 11 '15 at 16:33
  • @TheTrowser Actually you could nest classes/structs in C# already, and soon you can nest methods. – dss539 Mar 21 '16 at 20:56

7 Answers7

72

Update: Local functions where added in version 7 C#.

void OuterMethod()
{
    int foo = 1;
    InnerMethod();
    void InnerMethod()
    {
        int bar = 2;
        foo += bar
    }
}

In previous version C# you have to use action like this:

void OuterMethod()
{
    int anything = 1;
    Action InnedMethod = () =>
    {
        int PlitschPlatsch = 2;
    };
    InnedMethod();
}
Matan Shahar
  • 3,190
  • 2
  • 20
  • 45
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
42

UPDATE: C#7 added local functions (https://learn.microsoft.com/en-us/dotnet/articles/csharp/csharp-7#local-functions)

void OuterMethod()
{
    int foo = 1;

    InnerMethod();

    void InnerMethod()
    {
        int bar = 2;
        foo += bar
    }

}

In versions of C# before C#7, you can declare a Func or Action and obtain something similar:

void OuterMethod()
{
    int foo = 1;
    Action InnerMethod = () => 
    {
        int bar = 2;
        foo += bar;
    } ;

    InnerMethod();
}
jeroenh
  • 26,362
  • 10
  • 73
  • 104
  • @cheeso: Because it's an easy solution that the language supports so nicely – Jeff Yates May 04 '11 at 14:00
  • This will not work in C#. "Cannot assign anonymous method to an implicitly-typed local variable". –  Aug 08 '14 at 18:59
  • @nitro it works just fine. The example does not use an implicitly typed local variable (i.e. the `var` keyword). It did contain some typos though, which I fixed. – jeroenh Aug 09 '14 at 16:38
16

yes, there are ways. With C# 3.0 you have the Func<T> type that does this.

For example, I wrote this yesterday:

  var image = Image.FromFile(_file);
  int height = image.Height;
  int width = image.Width;
  double tan = height*1.00/width;
  double angle = (180.0 * Math.Atan(tan) / Math.PI);
  var bitmap = new System.Drawing.Bitmap(image, width, height);
  var g = System.Drawing.Graphics.FromImage(bitmap);
  int fontsize = 26; // starting guess
  Font font = null;
  System.Drawing.SizeF size;

  Func<SizeF,double> angledWidth = new Func<SizeF,double>( (x) =>
      {
          double z = x.Height * Math.Sin(angle) +
          x.Width * Math.Cos(angle);
          return z;
      });

  // enlarge for width
  do
  {
      fontsize+=2;
      if (font != null) font.Dispose();
      font = new Font("Arial", fontsize, System.Drawing.FontStyle.Bold);
      size = g.MeasureString(_text, font);
  }
  while (angledWidth(size)/0.85 < width);

The purpose was to add a watermark to an existing image. I wanted to make the size of the watermark text about 85% of the width of the image. But I wanted to cant the watermark text so that it was written on an angle. This revealed the need to do some trig calculations based on the angles, and I wanted a little function to perform that work. The Func is perfect for that.

The code above defines a Func (a function) that accepts a SizeF and returns a double, for the actual width of the text when it is drawn at the given angle. This Func is a variable within a function, and the variable itself holds a (reference to a) function. I can then invoke that "private" function within the scope where I've defined it. The Func has access to the other variables that are defined before it, in its execution scope. So, the angle variable is accessible within the angledWidth() function.


If you want invokable logic that returns void, you can use Action<T>, in the same way. .NET defines Func generics that accept N arguments, so you can make them pretty complicated. A Func is like a VB Function or a C# method that returns non-void; an Action is like a VB Sub, or a C# method that returns void.

Cheeso
  • 189,189
  • 101
  • 473
  • 713
9

Five years have passed since this question was asked and now C# 7 is coming.

It's slated to include local functions, and is apparently already implemented.

Local functions (Proposal: #259) [currently in future branch]

https://github.com/dotnet/roslyn/issues/259

dss539
  • 6,804
  • 2
  • 34
  • 64
  • 1
    I will note that, in my personal opinion, before you use this feature, you should strongly consider what you're doing. It's possible that your method is becoming too large to be easily readable. – dss539 Mar 21 '16 at 21:00
3

The delegate keyword does just that.

void OuterMethod()
{
    var InnerMethod = delegate()
    {
        int PlitschPlatsch = 2;
    };

    int anything = 1;
    InnerMethod();
}

Don't forget that, per scoping, the PlitschPlatsch variable won't be accessible outside InnerMethod.

zneak
  • 134,922
  • 42
  • 253
  • 328
  • 1
    @Cheeso Probably because there's just one good way to do it. Besides, it's not _exactly_ the same. – zneak May 04 '11 at 15:01
  • 4
    This will not work in C#. "Cannot assign anonymous method to an implicitly-typed local variable". –  Aug 08 '14 at 18:59
1

Take a look at anonymous methods. I think that's what you're looking for.

Abbas
  • 3,872
  • 6
  • 36
  • 63
T.K.
  • 2,229
  • 5
  • 22
  • 26
1

If you're looking mainly to "hide" a method that is just a "helper" ... another option is to make your helper(s) private. That way they don't become part of your class's public interface.

This has the advantage that the helper(s) can be reused if necessary; but it / they won't be "internal" to the calling method.

David
  • 2,226
  • 32
  • 39