C#Func<>和扩展方法问题

时间:2011-05-31 11:16:04

标签: c# .net lambda

我见过有人写下Func<>图案。我正在尝试使用Funcs和Lambdas来理解这些概念。

所以ExperimentalSelect返回一个Func(带有2个args和bool返回值)。

但是我不明白所有3个返回语句是如何有效的(每次1个)。

public static Func<BinaryTreeNode<int>, int, bool> nodeSelector = (x, y) =>
{
    return x.Value > y;
};

public static Func<int, int, bool> intSelector = (x, y) =>
{
    return x > y;
};


public static Func<BinaryTreeNode<int>, int, bool> ExperimentalSelect (int number)
{
    return nodeSelector; // seems straightforward, i agree this should work

    // how does this work ? intSelector is different type Func<> 
    // and it is executing it here, thereby returning the bool type result 
    // and not Func<> type as the return type of this method should
    return (x, y) => intSelector(number, number); 

    // and how does this work ? what is node here ? 
    // and SomeMethod returns bool and not Func<> type
    return (node, x) => SomeMethod(node, number, true); 
}

private static bool SomeMethod(BinaryTreeNode<int> node, int someNumber,
                               bool doSomething)
{
    return node.Value < someNumber;
}

编辑:

如果是分机。方法需要一个函数

IEnumerable<int> selected = tree.TakeWhile(ExperimentalSelect);
  1. SomeMethod如何在这里工作?,它不是Func&lt;&gt; !

  2. 此语法的含义是:(node, x) => SomeMethod(node, number, true);

  3. 这里的节点或x在哪里?

3 个答案:

答案 0 :(得分:4)

您在回复上方的评论不正确。

intSelectorSomeMethod 在那里执行。它们只会在执行ExperimentalSelect的返回值时执行。

return (x, y) => intSelector(number, number);

这定义了一个带有两个参数的匿名方法。类型为BinaryTreeNode<int>之一,类型为int且返回值为bool,因为这是ExperimentalSelect的返回类型。 此匿名方法的主体是对intSelector的调用,仅在执行匿名方法本身时执行。这意味着,这个匿名方法的主体可以是你想要的任何东西。它甚至可以是多个陈述:

return (x, y) => {
                      var temp;
                      temp = y;
                      y = x;
                      x = temp;
                      return intSelector(number, y);
                 }

然后返回匿名方法,而不是执行它的结果 您的退货声明等同于以下内容:

Func<BinaryTreeNode<int>, int, bool> result = 
    (x, y) => intSelector(number, number);
return result;

您可以使用调试器自行验证。在intSelector内添加一个断点,然后跳过return语句。你会看到,断点不会被击中。

重要的一点如下:

Func可以看作是函数的指针。

Func<BinaryTreeNode<int>, int, bool> result = 
    (x, y) => SomeMethod(x, number, true); 

这将创建一个匿名方法,result将指向该匿名方法。 但是,请查看以下代码:

Func<BinaryTreeNode<int>, int, bool, bool> result = SomeMethod;

在这种情况下,结果将直接指向SomeMethod。这里没有创建匿名方法。请注意result类型的差异。由于第一个代码仅在匿名方法的主体中执行SomeMethod,因此result的类型不需要与SomeMethod的签名匹配。但在第二个代码中,您直接将SomeMethod分配给result,因此result的类型必须与SomeMethod的签名匹配。

更多:
请查看以下代码:

public static Func<BinaryTreeNode<int>, int, bool> ExperimentalSelect (int number)
{
    return (x, y) => intSelector(number, number); 
}

Func<BinaryTreeNode<int>, int, bool> result = ExperimentalSelect(10);
Console.WriteLine(result(30, 20)); // writes false

它将打印false,虽然30大于20.为什么?
原因是,您的匿名方法具有xy作为输入参数,但它们不会在其正文中的任何位置使用。相反,您将number作为两个参数传递给intSelectornumber的值为10,而10不大于10 编写此代码的正确方法如下:

public static Func<BinaryTreeNode<int>, int, bool> ExperimentalSelect ()
{
    return (x, y) => intSelector(x, y); 
}

Func<BinaryTreeNode<int>, int, bool> result = ExperimentalSelect();
Console.WriteLine(result(30, 20)); // writes true

如您所见,我现在将xy传递给intSelector。我还从number中删除了参数ExperimentalSelect,因为它未在任何地方使用。

答案 1 :(得分:2)

问问自己 - 这两行代码是否正确:

Func<BinaryTreeNode<int>, int, bool> a = 
  (x, y) => intSelector(number, number);

Func<BinaryTreeNode<int>, int, bool> b =
  (node, x) => SomeMethod(node, number, true);  

答案 - 是的。正如代码中的return语句一样。

我想也许你或者稍微误解了语法,或者可能没有准确理解Func是什么(如果不是这样的话,道歉)。

答案 2 :(得分:2)

在这种情况下,您似乎认为

return (x, y) => intSelector(number, number); 

返回的是intSelector(number, number)部分。但实际上,return关键字之后的整个事情都是返回值。你可以像这样重写它:

return (BinaryTreeNode<int> x, int y) => intSelector(number,number);

大致相当于返回一个匿名委托,其中包含两个类型为BinaryTreeNode<int>int的参数,它们返回bool类型的值。所以这就是你的Func<BinaryTreeNode<int>, int, bool>

基本上,=>左边的部分描述了参数,右边的部分是方法体,整个事物的返回类型是体的返回类型。

看看Eric White的Lambda Expressions article,这对你来说很有意义。