Странная идея: C # - объявить метод в другом методе - PullRequest
0 голосов
/ 17 августа 2010

Хорошо, в python это можно сделать:

def foo(monkeys):
    def bar(monkey):
        #process and return new monkey
    processed_monkeys = list()
    for monkey in monkeys:
        processed_monkeys += bar(monkey)
    return processed_monkeys

(Это просто глупый пример). Иногда я пропускаю эту функцию объявления метода внутри другого метода в c #.Но сегодня у меня была следующая идея для достижения этой цели:

List<Monkey> foo(List<Monkey> monkeys)
{
    Func<Monkey, Monkey> bar = delegate(Monkey monkey)
    {
        //process and return new monkey
    }
    List<Monkey> processed_monkeys = new List<Monkey>(monkeys.Count);
    foreach(Monkey monkey in monkeys)
        processed_monkeys.Append(bar(monkey));
    return processed_monkeys;
}

Очевидно, что обходной путь не обеспечивает точно такую ​​же функциональность, как оригинал, так как делегаты Func или Action ограничены 4 параметрами, но более 4 параметрамиредко нужны ...

Что вы думаете по этому поводу?
Является ли это злом и его следует избегать во всех, кроме очень особых ситуациях?
Как это работает?Будет ли создаваться новая функция bar каждый раз, когда она вызывается, или компилятор каким-то образом ее оптимизирует?

Ответы [ 5 ]

5 голосов
/ 17 августа 2010

... поскольку делегаты Func или Action ограничены четырьмя параметрами ...

Начиная с .NET 4.0, эти типы делегатов определены для примерно до 17 параметров,Вы также можете определить свой собственный довольно просто для любого произвольного числа параметров;Например, ниже я определяю делегата, который принимает 5 параметров:

public delegate void Action<T1, T2, T3, T4, T5>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5);

Что вы думаете по этому поводу?

Это совершенно нормально.Верьте или нет, разработчики .NET делают это все время.

Это зло и его следует избегать для всех, кроме очень особых ситуаций?

Нет, это довольно мягко,В этом нет ничего страшного.

Как это производительность?Будет ли создаваться новая функция bar каждый раз, когда она вызывается, или компилятор каким-то образом ее оптимизирует?

Производительность довольно хорошая.Компилятор определит фактический полноценный тип CLR для предоставления анонимного метода, точно так же, как он определяет полноценные типы CLR для анонимных типов и для методов, использующих ключевое слово yield.Не волнуйся;анонимные методы не требуют динамической компиляции при каждом вызове!На самом деле, это было бы довольно абсурдно, если подумать.

Это даже не то, что я бы назвал "оптимизацией";это просто способ, которым анонимные методы реализуются компилятором.

2 голосов
/ 17 августа 2010

Это плохо, когда труднее читать твой код, хорошо, когда легче читать, иначе нейтрально.

2 голосов
/ 17 августа 2010

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

var bar = (monkey) => { return new Monkey(); }

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

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

0 голосов
/ 17 августа 2010

Я считаю, что это хорошо, только если конкретная подфункция будет использоваться только в этой функции.В противном случае вам придется повторить это, и это станет для меня злом.

0 голосов
/ 17 августа 2010

Я довольно часто использовал этот 'шаблон' в C # после изучения схемы.

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

...