此Func <T,TReturn>中的第一个箭头运算符是什么意思?

时间:2019-10-28 20:29:20

标签: c# expression-body

给出以下示例代码:

enum op
{ 
  add, 
  remove
}

Func<op, int> combo(string head, double tail) => 
  (op op) => 
  op == op.add ? Int32.Parse(head) + Convert.ToInt32(tail) : Int32.Parse(head) - Convert.ToInt32(tail);

Console.WriteLine(combo("1", 2.5)(op.remove));

哪个返回:

  

-1

第一个箭头运算符是什么意思?
按照规范,它看起来不像表达式主体或lambda运算符。
C# language specification中是否有关于此用法的参考?

2 个答案:

答案 0 :(得分:13)

  

第一个箭头运算符是什么意思?

在较新版本的C#中,您可以编写:

int M(int x) 
{
  return x + x;
}

更短更清晰:

int M(int x) => x + x;

无非就是“语法糖”,它使您能够以更短,更直接的方式编写简单的方法。

  

它看起来不像表达式主体或lambda运算符。

左侧的=>表示表达式主体。右边的=>表示一个lambda。因此,在您的示例中这有点令人困惑,因为返回的东西是lambda,它也使用=>。但不要让那分散您的注意力:

Func<int, int> M() => x => x + 1;

只是一种简短的书写方式

Func<int, int> M() 
{
  return x => x + 1;
}

反过来只是一种简短的写作方式

static int Anonymous(int x)
{
  return x + 1;
}
Func<int, int> M() 
{
  return Anonymous;
}

如果您发现带有多个=>运算符的代码令人困惑,则始终可以通过将其删除成更明确的形式来删除它们。这只是一些人觉得更容易阅读的简短形式。


  

你能写

static Func<op, int> combo(string head, double tail) =>
  (op op) => ...; 
  

只有一个=>运算符。

好的。这是两种等效的编写代码的方法。

// Block body, lambda return.
static Func<op, int> combo(string head, double tail)
{
  return (op op) => ...; 
}

// Block body, local function return:
static Func<op, int> combo(string head, double tail)
{
  op MyFunction(op)
  {
     return ...;
  }
  return MyFunction;
}
  

对不起,我没有被公开。我的意思是,您可以将lambda提取到它自己的独立函数中,就像过去的代码一样。

当然;那有点复杂。我们将通过一系列小步骤来做到这一点:

我们从这里开始:

Func<op, int> combo(string head, double tail) => 
  (op op) => 
    op == op.add ? Int32.Parse(head) + Convert.ToInt32(tail) : 
    Int32.Parse(head) - Convert.ToInt32(tail);

对外部函数进行糖化

Func<op, int> combo(string head, double tail)
{
  return (op op) => 
    op == op.add ? Int32.Parse(head) + Convert.ToInt32(tail) : 
    Int32.Parse(head) - Convert.ToInt32(tail);
}

将内部函数转换为帮助器:

static int Helper(string head, double tail, op op)
{
    return op == op.add ? Int32.Parse(head) + Convert.ToInt32(tail) : 
    Int32.Parse(head) - Convert.ToInt32(tail);
}

Func<op, int> combo(string head, double tail)
{
  return (op op) => Helper(head, tail, op);
}

现在将助手方法移至类:

private class Closure
{
  public int Helper(string head, double tail, op op)
  {
    return op == op.add ? Int32.Parse(head) + Convert.ToInt32(tail) : 
    Int32.Parse(head) - Convert.ToInt32(tail);
  }
}

Func<op, int> combo(string head, double tail)
{
  Closure c = new Closure();
  return (op op) => c.Helper(head, tail, op);
}

现在将闭合的头和尾成员制成:

private class Closure
{
  public string head;
  public double tail;
  public int Helper(op op)
  {
    return op == op.add ? Int32.Parse(head) + Convert.ToInt32(tail) : 
    Int32.Parse(head) - Convert.ToInt32(tail);
  }
}

Func<op, int> combo(string head, double tail)
{
  Closure c = new Closure();
  c.head = head;
  c.tail = tail;
  return (op op) => c.Helper(op);
}

现在我们可以对lambda进行除糖了:

private class Closure
{
  public string head;
  public double tail;
  public int Helper(op op)
  {
    return op == op.add ? Int32.Parse(head) + Convert.ToInt32(tail) : 
    Int32.Parse(head) - Convert.ToInt32(tail);
  }
}

Func<op, int> combo(string head, double tail)
{
  Closure c = new Closure();
  c.head = head;
  c.tail = tail;
  return c.Helper;
}

我们完成了。

如果使用ILDASM或sharplab.io或某些此类工具对代码进行反编译,您会发现这正是编译器为您的代码生成的内容,只是它会为助手生成奇怪的非法名称,以确保您永远不会意外误称其中之一。

答案 1 :(得分:2)

以lambda形式返回函数的函数,也许可能更易于理解,以“旧”方式编写,仅出于解释的目的,认为params闭包不是理想的:

        string head;
        double tail;
        private int innerFunc(op op )
        {
            return op == op.add ? Int32.Parse(head) + Convert.ToInt32(tail) : Int32.Parse(head) - Convert.ToInt32(tail);
        }

        Func<op, int> comboWihoutLambda (string headprm, double tailprm)
        {
            head = headprm;
            tail = tailprm;
            return innerFunc;

        }