C#:Func<>而不是方法?

时间:2011-08-24 07:40:52

标签: c# .net linq c#-4.0 func

这是一个好奇的问题,你们都知道:

使用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 ...*/ };
}

6 个答案:

答案 0 :(得分:11)

我看到了几个缺点:

  • 性能影响(委托与方法) - 很小但是就在那里
  • 没有参数名称(在通话时伤害可读性)
  • 定义本身不太可读
  • 没有过载可能(感谢xanatos)

因为你没有获得任何东西,我只会在局部和小的环境中这样做,而更喜欢静态方法

答案 1 :(得分:5)

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

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

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

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

答案 2 :(得分: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方法是有道理的。但是如果你没有使用它,你已经引入了一个间接层次太多,对性能的影响,代码传达其意图的程度以及程序的正确性(因为你的方法现在可以切换到另一个在运行时做一些不同的事情)

答案 3 :(得分:2)

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

如果你有充分的理由使用它,就像你根据某些条件动态创建Func然后使用Func&lt;&gt;是有道理的..

另请参阅Action。这是一个我读过的博客,解释何时使用:http://simpleprogrammer.com/2010/09/24/explaining-what-action-and-func-are/

答案 4 :(得分:2)

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

  • 性能影响小,因为lambdas / delegates比方法慢一点
  • 参数具有通用名称(例如arg1arg2
  • Intellisense通常无法提供文档工具提示
  • 定义为lambda字段的方法无法引入新的通用参数
  • 可读性影响

答案 5 :(得分: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;