C #: функция в функции возможна? - PullRequest
61 голосов
/ 04 мая 2011

Можно ли объявить метод в другом методе в C #?

Например, вот так:

void OuterMethod()
{
    int anything = 1;
    InnedMethod();
    void InnerMethod()
    {
        int PlitschPlatsch = 2;
    }
}

Ответы [ 7 ]

55 голосов
/ 04 мая 2011

Обновление: Локальные функции , добавленные в версии 7 C #.

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

В предыдущей версии C # вы должны использовать действие, подобное этому:

void OuterMethod()
{
    int anything = 1;
    Action InnedMethod = () =>
    {
        int PlitschPlatsch = 2;
    };
    InnedMethod();
}
41 голосов
/ 04 мая 2011

ОБНОВЛЕНИЕ: C # 7 добавлены локальные функции (https://docs.microsoft.com/en-us/dotnet/articles/csharp/csharp-7#local-functions)

void OuterMethod()
{
    int foo = 1;

    InnerMethod();

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

}

В версиях C # до C # 7 вы можете объявить Func или Action и получить нечто подобное:

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

    InnerMethod();
}
16 голосов
/ 04 мая 2011

да, есть способы. С C # 3.0 у вас есть тип Func<T>, который делает это.

Например, я написал это вчера:

  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);

Цель состояла в том, чтобы добавить водяной знак к существующему изображению. Я хотел, чтобы размер водяного знака составлял около 85% ширины изображения. Но я хотел наклонить текст водяного знака так, чтобы он был написан под углом. Это выявило необходимость выполнения некоторых триггерных вычислений на основе углов, и мне нужна была небольшая функция для выполнения этой работы. Func идеально подходит для этого.

Приведенный выше код определяет Func (функция), которая принимает SizeF и возвращает double для фактической ширины текста, когда он рисуется под заданным углом. Эта Func является переменной внутри функции, а сама переменная содержит функцию (ссылку на a). Затем я могу вызвать эту «приватную» функцию в той области, где я ее определил. Func имеет доступ к другим переменным, которые определены перед ним, в своей области выполнения. Таким образом, переменная angle доступна в функции angledWidth().


Если вам нужна активируемая логика, которая возвращает void, вы можете использовать Action<T> таким же образом. .NET определяет дженерики Func, которые принимают N аргументов, поэтому вы можете сделать их довольно сложными. Func - это как функция VB или метод C #, который возвращает не void; Действие похоже на VB Sub или метод C #, который возвращает void.

9 голосов
/ 21 марта 2016

Прошло пять лет с тех пор, как этот вопрос был задан, и сейчас идет C # 7.

Планируется включить локальные функции и, по-видимому, уже реализовано.

Локальные функции (Предложение: # 259) [в настоящее время в будущей ветке]

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

3 голосов
/ 04 мая 2011

Ключевое слово delegate делает именно это.

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

    int anything = 1;
    InnerMethod();
}

Не забывайте, что, согласно определению, переменная PlitschPlatsch не будет доступна вне InnerMethod.

1 голос
/ 04 мая 2011

Если вы хотите «скрыть» метод, который является просто «помощником» ... другой вариант - сделать ваш помощник (и) private.Таким образом, они не становятся частью открытого интерфейса вашего класса.

Это имеет то преимущество, что помощник (и) может быть повторно использован при необходимости;но это / они не будут "внутренними" для вызывающего метода.

1 голос
/ 04 мая 2011

Взгляните на анонимные методы . Я думаю, это то, что вы ищете.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...