13

这是大家都知道的好奇问题:

使用 Func 而不是方法有什么危害/缺点吗?简单的例子:

private static Func<int, int, DBContext, List<T>> Foo =
    (i1, i2, dbc) =>
        (i1 != 0) ? dbc.Bar(i2) : new List<T> { /*some default values ...*/ };

VS

private static List<T> Foo(int i1, int i2, DBContext dbc)
{
    return i1 != 0 ? dbc.Bar(i2) : new List<T> { /*some default values ...*/ };
}
4

6 回答 6

11

我看到几个缺点:

  • 性能影响(委托与方法) - 小但存在
  • 没有参数名(损害调用的可读性)
  • 定义本身的可读性较差
  • 不可能超载(感谢 xanatos)

当您一无所获时,我只会在本地和小型环境中这样做,并且更喜欢静态方法

于 2011-08-24T07:45:06.770 回答
5

性能并不像最初看起来那么重要,调用委托和通过v_table(虚拟实例方法)调度的方法的成本是可比的。在这种情况下,对于静态方法,不使用委托可能会带来很小的性能提升。

您在此处发现的“技巧”是一种相当常见的技术,无需借助面向对象的编程技术(例如策略模式)即可实现功能分解。您将方法调用替换为对委托的调用。这个技巧的另一个优点是调用的语法是相同的。

但是,我会非常小心地应用这种技术。我通常使用它来避免使用单一方法的接口,这些接口不具有超过一个或两个参数(否则我会考虑使用参数对象或使用接口)。

C# 是一种多范式语言,使用每种范式都有其位置。函数式范式(例如使用 Funcs 而不是编译时已知方法)和面向对象的范式一样有它们的位置。在您的情况下,使用 a 没有任何好处Func<>,您应该使用传统方法来代替。

于 2011-08-24T07:54:45.750 回答
4

在第一种情况下(使用 Func),您编写的不是方法,而是使用特定委托初始化的变量 Foo。您有一个间接级别,可用于更改 Foo 指向的内容。为了简化您的示例:

public static class Test {

    public static Func<int, int, int> Foo =
        (i1, i2) =>
            i1 + i2;

    public static int Foo2(int i1, int i2)
    {
        return i1 + i2;
    }
}

让我们测试一下:

int a = Test.Foo(2,3);
int b = Test.Foo2(2,3);

Console.WriteLine("{0}, {1}",a,b); // 5, 5, all seems good, they're both sums

    //... but wait... now you can do this:
Test.Foo = (x,y) => x * y; //reassigning Foo
int c = Test.Foo(2,3);
Console.WriteLine("{0}",c); // 6 

因此,如果您使用这种间接级别,则 Func 方法是有意义的。但是,如果您不使用它,那么您已经引入了太多的间接级别,这会影响性能、代码传达其意图的程度以及程序的正确性(因为您的方法现在可以切换到另一个在运行时做一些不同的事情)

于 2011-08-24T08:01:14.897 回答
2

理想情况下,如果始终只有一个 Func 定义,则您不会想要创建它。您会不必要地增加代码的复杂性和可读性,从而影响可维护性。

如果您有充分的理由使用它,例如根据某些条件动态创建 Func,那么使用 Func<> 是合理的。

也看看行动。这是我阅读的一个博客,用于解释何时使用什么:http ://simpleprogrammer.com/2010/09/24/explaining-what-action-and-func-are/

于 2011-08-24T07:48:27.343 回答
2

从“学习书”的角度来看应该是一样的,但是

  • 对性能的影响很小,因为 lambdas/delegates 比方法慢一点
  • 参数具有通用名称(例如arg1, arg2
  • Intellisense 通常无法提供文档工具提示
  • 定义为 lambda 字段的方法不能引入新的泛型参数
  • 可读性影响
于 2011-08-24T07:55:36.200 回答
1

除了可读性降级之外,我认为没有任何其他危害。不确定代码是如何编译的,但在第一个版本中,您只是使用委托定义函数。我想您还可以执行以下操作:

private static List<T> Foo(int i1, int i2, DBContext dbc)
{
    i1 != 0 ? return dbc.Bar(i2) : return new List<T> { /*some default values ...*/ };
}

private static Func<int, int, DBContext, List<T>> Foo2 = Foo;
于 2011-08-24T07:45:07.860 回答