简体   繁体   English

这个 Func 中的第一个箭头运算符是什么<t, treturn>意思是?</t,>

[英]What does the first arrow operator in this Func<T, TReturn> mean?

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 -1

What does the first arrow operator mean?第一个箭头运算符是什么意思?
By specification it does not look like an expression body or a lambda operator.按照规范,它看起来不像表达式主体或 lambda 运算符。
Is there any reference in the C# language specification about this usage? C# 语言规范中是否有关于此用法的参考?

What does the first arrow operator mean?第一个箭头运算符是什么意思?

In newer versions of C#, you are allowed to write:在较新版本的 C# 中,您可以编写:

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.它看起来不像表达式主体或 lambda 运算符。

The left => indicates an expression body.左边的=>表示表达式主体。 The right => indicates a lambda.右边=>表示 lambda。 So it is somewhat confusing in your example because the thing being returned is a lambda, which also uses => .因此,在您的示例中有点令人困惑,因为返回的东西是 lambda,它也使用=> 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.我的意思是,请您将 lambda 提取到它自己的独立 function 中,就像过去人们会做的那样。

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:将外层 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:将内部的 function 变成助手:

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:现在将辅助方法移动到 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:现在我们可以对 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.如果您使用 ILDASM 或 sharplab.io 或一些此类工具反编译您的代码,您会发现这正是编译器为您的代码生成的内容,除了它为帮助程序生成奇怪的非法名称以确保您永远不会意外调用其中一个他们错误地。

Function that returns function, maybe easier to understand without lambda, written in "old" way, just for explanation, think that params closure is not ideal: Function 返回 function,没有 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;

        }

Think that => is the inversed logic Material implication used to define lambda expressions in C#.认为=>是用于在 C# 中定义 lambda 表达式的逻辑材料蕴涵

It means that the result of the left operand is obtained by evaluating the right operand, like an equality.这意味着左操作数的结果是通过对右操作数求值得到的,就像等式一样。

So evaluating the left operand implies to evaluate the right operand.所以评估左操作数意味着评估右操作数。

So it is more like an equivalence <=> but since it is made to use the left operand in expression, the operator is => : writting left operand in an expression implies to use the right operand in place.所以它更像是一个等价<=>但由于它是在表达式中使用左操作数,因此运算符是=> :在表达式中写入左操作数意味着在适当的位置使用右操作数。

I say inversed because you can mathematically read: right operand implies left operand .我说inversed是因为你可以在数学上阅读:右操作数意味着左操作数

It is not equality operator, reserved for assignments, because there is a little difference.它不是相等运算符,保留用于赋值,因为有一点区别。

So here, calling combo (left operand) "replace" it by its definition (right operand).所以在这里,调用combo (左操作数)将其“替换”为它的定义(右操作数)。

And with the code you provided there is an imbrication between 2 lambdas expressions...使用您提供的代码,两个 lambdas 表达式之间存在重叠......

So we pass "double" parameters like a "bidimentional jagged array" because combo returns a Func<> .所以我们像“双向锯齿状数组”一样传递“双”参数,因为combo返回一个Func<>

So the first () is the combo parameters and the second () is the returned Func parameters.所以第一个()combo参数,第二个()是返回的Func参数。

Explained in a vulgarized and dubious way but I hope this will help you to understand.以粗俗和可疑的方式解释,但我希望这能帮助您理解。

Lambda Expressions in C#C# 中的 Lambda 表达式

Anatomy of the Lambda ExpressionLambda 表达式的剖析

C# - FuncC# - 功能

Lambda expressions (C# Programming Guide) Lambda 表达式(C# 编程指南)

The code of your question can be written as:你的问题的代码可以写成:

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

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM