给出以下示例代码:
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中是否有关于此用法的参考?
答案 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;
}