0

好的,在 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 Delegates 仅限于 4 个参数,但很少需要超过 4 个参数......

您对此有何看法?
这是邪恶的吗?除了非常特殊的情况外,应该避免所有情况吗?
这个表现如何?每次调用函数时都会创建一个新的 bar 函数,还是编译器会以某种方式对其进行优化?

4

5 回答 5

5

...因为 Func 或 Action Delegates 仅限于 4 个参数...

从 .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 类型来提供匿名方法,就像它为匿名类型和使用yield关键字的方法定义完整的 CLR 类型一样。不用担心; 匿名方法不会在每次调用时产生动态编译!真的,如果你仔细想想,那将是非常荒谬的。

这甚至不是我所说的“优化”。这只是编译器实现匿名方法的方式。

于 2010-08-17T12:44:56.907 回答
2

您可以使用 lambda 表达式语法,因此代码会更短一些,并且您不会被限制为 4 个参数。

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

恕我直言,这不是邪恶的。委托肯定会编译一次,因此委托和静态方法之间的性能差异不会很大。

当然,和往常一样,这种技术不应该被过度使用,以避免创建不可读/不可维护的代码。

于 2010-08-17T12:46:57.590 回答
2

当它使您的代码更难阅读时是邪恶的,当它使您的代码更容易阅读时是好的,否则是中立的。

于 2010-08-17T12:49:14.453 回答
0

在学习了 Scheme 之后,我在 C# 中经常使用这种“模式”。

创建捕获可用作延续函数的值的闭包非常方便(尤其是在异步使用时)。

于 2010-08-17T12:50:03.263 回答
0

仅当特定子功能仅在此功能中使用时,我才认为它很好。否则你将不得不重复它,它对我来说变得邪恶。

于 2010-08-17T12:51:21.697 回答