Search code examples
c#pythonmethodsanonymous-methods

Weird idea: C# - declare a method insinde another method


Okay, in python one can do this:

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

(This is just a stupid example) I sometimes miss this functionality of declaring a method inside another method in c#. But today I had the following idea for accomplishing this:

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

Obviously the workaround does not provide exactly the same functionality as the original as the Func or Action Delegates are limited to 4 parameters, but more than 4 parameters are rarely needed...

What are your opinions on this?
Is this evil and should be avoided for all but very special situations?
How is the performance of this? Will a new bar function be created each time the function is called, or will the compiler optimize this somehow?


Solution

  • ...as the Func or Action Delegates are limited to 4 parameters...

    Starting with .NET 4.0, these delegate types are defined for up to something like 17 parameters. You can also define your own quite simply for any arbitrary number of parameters; for example, below I define a delegate that takes 5 parameters:

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

    What are your opinions on this?

    It's totally fine. Believe or not, .NET developers do this all the time.

    Is this evil and should be avoided for all but very special situations?

    Nope, it's pretty benign. There's really no harm in it.

    How is the performance of this? Will a new bar function be created each time the function is called, or will the compiler optimize this somehow?

    The performance is pretty good. The compiler will define an actual full-blown CLR type to provide the anonymous method, just like it defines full-blown CLR types for anonymous types and for methods using the yield keyword. Don't worry; anonymous methods do not incur dynamic compilation on every invocation! Really, that would be pretty absurd, if you think about it.

    This isn't even really what I'd call "optimization"; it's simply the way that anonymous methods are implemented by the compiler.