Подтвердить что ты не робот

Вложенные методы? Почему они полезны?

Итак, я просто изучаю некоторые новые вещи на С# и Python. Оказывается, оба lanuages ​​поддерживают вложенные методы (тип С#).

Python:

def MyMethod():

    print 'Hello from a method.'

    def MyInnerMethod():
        print 'Hello from a nested method.'

    MyInnerMethod()

С# (с использованием новых функций в .NET 3.5): *

static void Main()
{
    Console.WriteLine("Hello from main.");

    Func<int, int> NestedMethod =
        (x) =>
        {
            Console.WriteLine("In nested method. Value of x is {0}.", x);
            return x;
        };

    int result = NestedMethod(3);
}

Итак, почему вложенные методы так важны? Что делает их полезными?


** Код С# не был протестирован. Не редактируйте, если он не компилируется. *

4b9b3361

Ответ 1

Во-первых, поймите, что я не могу дать вам полный список. Если бы вы спросили: "Почему отвертки полезны?", Я хотел бы поговорить о винтах и ​​крышках для красок, но пропустил бы их ценность в инспекции термитов. Когда вы спрашиваете: "Почему вложенные функции полезны?", Я могу рассказать вам о области видимости, закрытиях и точках входа.

Во-первых, вложенность может быть альтернативой классам. Недавно я написал некоторый код рендеринга, который взял имя файла для специализированного кода разметки и вернул растровое изображение. Это, естественно, приводит к функциям с именем grab_markup_from_filename() и render_text_onto_image() и другими. Самая чистая организация была одной точкой входа с именем generate_png_from_markup_filename(). Точка входа выполнила свою работу, используя вложенные функции для выполнения своей задачи. Класс не нужен, потому что не было объекта с состоянием. Моей альтернативой было создать модуль с частными методами, скрывающими моих помощников, но это было бы более беспорядочно.

def generate_png_from_markup_filename(filename):
    def grab_markup_from_filename():
        ... 
    ... # code that calls grab_markup_from_filename() to make the image
    return image

Во-вторых, я использую гнездование для закрытия. Наиболее распространенным примером является создание декораторов. Фокус в том, что я возвращаю ссылку на внутреннюю функцию, так что внутренняя функция и внешнее значение параметра не собираются в мусор.

def verify_admin(function_to_call):
    def call_on_verify_admin(*args, **kwargs):
        if is_admin(global.session.user):
            return function_to_call(*args, **kwargs)
        else:
           throw Exception("Not Admin")
    return call_on_verify_admin  # the return value of verify_admin()

используйте его следующим образом:

 def update_price(item, price):
     database.lookup(item).set_field('price', price)
 update_price = verify_admin(update_price)

или, более кратко:

 @verify_admin
 def update_price(item, price):
     database.lookup(item).set_field('price', price)

И да, это должно быть трудно проследить. Помните, что "def" - ​​это просто другое утверждение.

Итак, вот два места вложенных классов полезны. Их больше. Это инструмент.

Ответ 2

Вложенные методы полезны, потому что есть много случаев, когда вы хотите передавать поведение, а не просто данные. Во многих случаях проще и проще следовать, в дополнение к тому, чтобы проще и быстрее писать, чтобы просто определить это поведение в теле вашего метода, где вы собираетесь его использовать.

В .NET LINQ - отличный пример. Предположим, вы хотели создать список, в котором каждое значение было бы вдвое больше его значения в исходном списке:

list.Select(i => i*2)

где i => i*2 эквивалентно:

Func<int,int> double = delegate(int x) { return x*2; }

Это намного проще и понятнее, чем создание отдельной функции.

Кроме того, функция, которую вы объявляете, может не иметь значения в другом месте (т.е. вне области вашего метода). В С# вы можете даже ссылаться на переменные, объявленные внутри вашего тела метода - что вы не можете сделать с не-вложенной функцией.

Конечно, вы также можете злоупотреблять вложенными функциями...

Ответ 3

Вложенные методы также позволяют вам управлять областью вызова вызывающего, а также позволять вам получать доступ к внутренне созданным членам, не подвергая их другим функциям в аналогичной области (например, внутри класса).

Ответ 4

Вложенные методы увеличивают локальность вашего кода, что хорошо, поскольку вам не нужно загрязнять классы небольшими частными методами, которые используются только в одном месте.

Ответ 5

Попробуйте этот пример Pythonish pseudocode, чтобы заглянуть в один прецедент для этого метода:

def MyMethod(base):
    base = expensivePreparation(base)
    def MyInnerMethod(some_modifier):
        doSomethingCoolWith(base, some_modifier)

    return MyInnerMethod

process = MyMethod(some_obj)
process(arg1)
process(arg2)

Ответ 6

Вдоль вышеупомянутых пунктов они могут рассматриваться как Функции более высокого порядка, функции, которые сами принимают или возвращают функции.

Посмотрите этот пример:

     static void Main(string[] args)
    {

        Func<int, int> NestedMethod = delegate(int x)     
        {             Console.WriteLine("In nested method. Value of x is {0}.", x);        
            return x;         
        };

        HigerOrderTest(NestedMethod)();
    }

     private static Action HigerOrderTest(Func<int, int> highFunction)
    {
          var sam = highFunction(3);

          Action DoIt =() =>
          {
              Console.WriteLine("Output is {0}.", sam);    
          };
             return DoIt;
    }

Ответ 7

Здесь много полезных ответов, но здесь идет.

  • внутренние классы: нет! хорошая попытка, но слишком много make-work. Вложенные функции /procs намного быстрее и точнее. Король Java [1] классы с одним методом [2] действительно сосут, а вложенные функции (или процедуры) обходят эту синтаксическую бессмыслицу. Функциональная декомпозиция
  • : разбить длинную рутину на более мелкие, которые скрыты от других мест, где они не используются. Паскаль поддерживал это несколько лет назад, и я уверен, что это было не новое изобретение даже тогда (начало 70-х годов).
  • закрытие: упоминается в другом месте, но полезно. используйте локальные переменные в закрывающей функции для инициализации сгенерированной функции и возвратите настроенную функцию (или иначе используйте сгенерированный код).

1: http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of-nouns.html "Король Java"

2: http://en.wikipedia.org/wiki/Function_object#In_Java "Функциональный объект/функтор"

Ответ 8

Возможно, вы уже знаете о полезности передачи функций другим функциям, например, предоставляя подпрограмму sort() функцию сравнения и очевидные примеры map() и filter() и т.д. Аналогично, часто бывает полезно получать функции в результате от другой функции. Наиболее распространенное использование для закрытия, но currying также является общим.

Центральным преимуществом закрытия является возможность создания новой функции во время выполнения, которая содержит всю временную информацию, необходимую для ее выполнения в этот момент времени. В языковых реализациях, которые не поддерживают закрытие, такое управление состоянием обычно выполняется, возможно, менее элегантно, через классы: переменные экземпляра объекта устанавливаются, а затем затем считываются, когда это необходимо. Закрытие обеспечивает средство для объединения состояния с действием.

Итак, в качестве основной точки зрения, это может помочь думать о вложенных функциях как о способе написания функций "на месте" для выполнения очень конкретных действий, когда детали этих действий будут известны во время выполнения, но вы только хотите выполнить это действие в более позднее время.

Есть другие вещи, которые могут быть выполнены с вложенными функциями, но вы должны что-то начать.