问题
Given this example code:
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));
Which returns:
-1
What does the first arrow operator mean?
By specification it does not look like an expression body or a lambda operator.
Is there any reference in the C# language specification about this usage?
回答1:
What does the first arrow operator mean?
In newer versions of C#, you are allowed to write:
int M(int x)
{
return x + x;
}
as the shorter and clearer:
int M(int x) => x + x;
It is nothing more than a "syntactic sugar" that lets you write a simple method in a shorter and more direct way.
it does not look like an expression body or a lambda operator.
The left =>
indicates an expression body. The right =>
indicates a lambda. So it is somewhat confusing in your example because the thing being returned is a lambda, which also uses =>
. But do not let that distract you:
Func<int, int> M() => x => x + 1;
is just a short way of writing
Func<int, int> M()
{
return x => x + 1;
}
Which in turn is just a short way or writing
static int Anonymous(int x)
{
return x + 1;
}
Func<int, int> M()
{
return Anonymous;
}
If you find code with multiple =>
operators confusing you can always remove them by desugaring them into the more explicit form. It's just a short form that some people find easier to read.
Can you please write
static Func<op, int> combo(string head, double tail) =>
(op op) => ...;
with just one
=>
operator.
Sure. Here are two equivalent ways to write that code.
// 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;
}
Sorry, I was not being explicit. What I meant was can you please extract the lambda into its own standalone function, like what one would do in the olden days.
Sure; that is a little more complicated. We will do it in a series of small steps:
We start with this:
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);
Desugar the outer function:
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);
}
Turn the inner function into a helper:
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);
}
Now move the helper method to a class:
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);
}
Now make head and tail members of closure:
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);
}
And now we can desugar the 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;
}
And we're done.
If you decompile your code using ILDASM or sharplab.io or some such tool you will discover that this is exactly what the compiler generates for your code, except that it generates weird, illegal names for the helpers to ensure that you never accidentally call one of them by mistake.
回答2:
Function that returns function, maybe easier to understand without lambda, written in "old" way, just for explanation, think that params closure is not ideal:
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;
}
来源:https://stackoverflow.com/questions/58597957/what-does-the-first-arrow-operator-in-this-funct-treturn-mean