简体   繁体   English

我似乎无法在c#中围绕Lambdas

[英]I just can't seem to get my head around Lambdas in c#

I haven't really been able to get a firm grasp on creating and using lambda expressions. 我还没有真正掌握创建和使用lambda表达式的方法。 I know how to use them in linq statements, but I really don't understand what's going on behind the scenes. 我知道如何在linq语句中使用它们,但我真的不明白幕后发生了什么。 I also havent been able to find a complete tutorial on when to use them, how to define them, etc. 我还没能找到关于何时使用它们,如何定义它们等的完整教程。

Second part... 第二部分...

They say that Javascript is a LAMBDA language, I know javascript fairly well, just wondering what types of concepts that apply to javascript lambdas and c# lambdas. 他们说Javascript是一种LAMBDA语言,我比较熟悉javascript,只是想知道哪些类型的概念适用于javascript lambdas和c#lambdas。

thrid part... 第三部分......

what is the difference between a functional language and an lambda language? 函数式语言和lambda语言有什么区别?

Any suggestions? 有什么建议么?

Let me give you the scoop on what's going on behind the scenes. 让我向您介绍一下幕后发生的事情。 It is more straightforward than you think. 它比你想象的要简单明了。

Suppose you have: 假设你有:

delegate int D(int x);
...
class C
{
    void M(int y)
    {
        int z = 123;
        D d = x=>x+y+z;
        Console.WriteLine(d(10));
        z = 345;
        y = 789;
        Console.WriteLine(d(10));
   }
}

All the compiler does is pretends that you wrote: 所有编译器都假装你写的:

delegate int D(int x);
...
class C
{  
    private class Locals
    {
        public int y;
        public int z;
        public int A(int x)
        {
            return x + this.y + this.z;
        }
    }
    void M(int y)
    {
        // Initialize the closure class:

        Locals locals = new Locals();
        locals.y = y;

        // Transform the body so that all usages of y, z and the lambda
        // refer to the closure class:

        locals.z = 123;
        D d = locals.A;
        Console.WriteLine(d(10)); // Calls locals.A(10)
        locals.z = 345;
        locals.y = 789;
        Console.WriteLine(d(10)); // Calls locals.A(10)

    }
}

That's all there is to it. 这里的所有都是它的。 A lambda is just a compact syntax for writing "hoist all the outer local variables used by the lambda into a class, make a method on the class with a given body, and make me a delegate out of that method". lambda只是一个紧凑的语法,用于编写“将lambda使用的所有外部局部变量提升到一个类中,使用给定的主体在类上创建一个方法,并使我成为该方法的委托”。

Function closures in JScript work essentially the same way. JScript中的函数闭包工作方式基本相同。 JScript of course is not a class-based language so the details are slightly different, but the idea is the same. JScript当然不是基于类的语言,所以细节略有不同,但想法是一样的。 In C#, the newly created delegate object keeps track of the locals class, which has the variable state. 在C#中,新创建的委托对象跟踪具有变量状态的locals类。 In JScript, the newly created function object has a reference to the activation frame of the function which created the closure, which is basically the same information. 在JScript中,新创建的函数对象具有对创建闭包的函数的激活框的引用,这基本上是相同的信息。

The way lambdas are converted to expression trees is rather different, but this should at least get you started in understanding the idea of lambdas. lambdas转换为表达式树的方式是相当不同的,但这至少应该让你开始理解lambdas的概念。

I can't answer part three, but let me take a swing at 1 & 2 and maybe that will help you with 3. 我不能回答第三部分,但让我在1和2挥杆,也许这将帮助你3。

Do you understand delegates? 你了解代表吗? Because that's really all you're dealing with. 因为那真的是你所要处理的。 The VS2010 documentation is very succinct on this. VS2010 文档非常简洁。

At the root, a lambda is just an anonymous function passed into a delegate declaration. 在根目录下,lambda只是一个传递给委托声明的匿名函数。 Or, put more simply method without the signature (return type, name, and parameters). 或者,更简单的方法是没有签名(返回类型,名称和参数)。 The signature is implied by the usage. 签名由使用暗示。

Asking "when to use a lambda" is really asking the question "when should I use an anonymous function for a delegate" and really, I can't think of better scenarios than the ones LINQ uses them for as examples. 询问“何时使用lambda”实际上是在问“什么时候我应该为委托使用匿名函数”,实际上,我想不出更好的场景,而不是LINQ使用它们作为示例。 AFAIK and understand, Javascript is a lambda language because you can pass methods around like variables and do so with anonymous methods, not just declared methods. AFAIK并且理解,Javascript是一种lambda语言,因为你可以像变量一样传递方法,并使用匿名方法,而不仅仅是声明的方法。

As far as reading a lambda, I don't like the "goes to" terminology used by some. 至于阅读lambda,我不喜欢某些人使用的“转到”术语。 I tend to read it like a normal method, which is to say: 我倾向于像普通方法一样阅读它,也就是说:

"given some list of parameters, execute this code" “给定一些参数列表,执行此代码”

So, row=> row.State == "NY" means "Given row, return true when row's State is New York". 因此,row => row.State ==“NY”表示“给定行,当行的状态为纽约时返回true”。

Maybe I'm oversimplifying, but I'm a simple guy. 也许我过于简单了,但我是一个简单的人。

I can address the JavaScript part. 我可以解决JavaScript部分。 Because you can declare anonymous functions in JS ( var fn = function(){/* stuff */}; , you can also pass those functions as parameters to other functions. In fact, you've already used lambdas if you've ever had to do a custom sort routine. For example: 因为你可以在JS中声明匿名函数( var fn = function(){/* stuff */}; ,你也可以将这些函数作为参数传递给其他函数。事实上,你已经使用了lambdas必须做一个自定义排序例程。例如:

// Standard sort:
x = [4,3,6,7,1,5,2];
x.sort();

// Custom sort:
y = [
    {'val':4,'name':'four'},
    {'val':3,'name':'three'},
    {'val':6,'name':'six'},
    {'val':7,'name':'seven'},
    {'val':1,'name':'one'},
    {'val':5,'name':'five'},
    {'val':2,'name':'two'},
];
y.sort(function(a,b){ return a.val > b.val ? 1 : -1 });

replace() is another example that takes lambda functions as parameters. replace()是另一个将lambda函数作为参数的示例。

Doing this in your own code is pretty easy, though in practice I never found a circumstance when this couldn't be done more clearly some other way (if anyone else needs to manager your code, you're guaranteed to break their head until they see the lambda). 在您自己的代码中执行此操作非常简单,但在实践中我从未发现过某种情况,如果其他方式无法更清楚地完成此操作(如果其他人需要管理您的代码,那么您肯定会在他们的代码之前打破他们的头脑看到lambda)。

Here's an example. 这是一个例子。 Say you have a Widget object that produces some form of output. 假设您有一个Widget对象,它会产生某种形式的输出。 You know it will always produce output, but you don't know what form that output will take. 您知道它将始终生成输出,但您不知道该输出将采用何种形式。 One solution is to pass into the object the method it needs to generate that output. 一种解决方案是将生成该输出所需的方法传递给对象。 Here's a simple implementation: 这是一个简单的实现:

First, the Widget itself. 首先, Widget本身。 Note that Widget.prototype.publish() takes a single parameter, which is your custom formatter: 请注意, Widget.prototype.publish()接受一个参数,这是您的自定义格式化程序:

var Widget = function() {
    var self = this;
    var strPrivateVar = "This is a private variable";
    self.publicVar = "This is a default public variable";
    self.publish = function(f) {
        var fnFormatter = f;
        var strOutput = "The output is " + fnFormatter(self,strPrivateVar);
        return strOutput;
    }
};

Next, your formatters. 接下来,您的格式化程序。 One gives a brief summary while the other gives the full text: 一个给出了简短的总结,而另一个给出了全文:

var fnSummary = function(o,s) {
    var self = o;
    var strPrivateVar = s;
    return strPrivateVar.substr(0,5) + ' ' + self.publicVar.substr(0,5);
}
var fnDetails = function(o,s) {
    var self = o; 
    var strPrivateVar = s;
    return strPrivateVar + ' ' + self.publicVar;
}

And last, your implementation: 最后,你的实施:

var wWidget = new Widget();
wWidget.publicVar = "I have overridden the public property";
var strSummary = wWidget.publish(fnSummary);
var strDetails = wWidget.publish(fnDetails);
console.log(strSummary,strDetails);

This solution means you don't need to alter the wWidget object to get the desired output. 此解决方案意味着您无需更改wWidget对象即可获得所需的输出。 Due to scoping issues, you do have to jump through some hoops to get the variables from the object into the publisher methods, but once you do that the rest is easy. 由于存在范围问题,您必须跳过一些环节以将对象中的变量转换为发布方法,但是一旦您这样做,其余部分就很容易了。

I know there are others on SO that could give a better example, but I hope this helps you. 我知道有其他人可以提供一个更好的例子,但我希望这会对你有所帮助。

果壳中的C#3以及Jon Skeet的书在他们的书中很好地解决了这个问题。

A lambda expression is an anonymous, first-class function. lambda表达式是一个匿名的一流函数。 When you declare one, you create a function that is addressable, but can have any number of aliases, just like an object (hence, first-class). 当你声明一个,你创建一个可寻址的函数,但可以有一个别名,就像一个对象(因此,第一类)。 You can pass it around in variables and parameters. 您可以在变量和参数中传递它。 Javascript can be called a lambda language because all javascript functions have these properties. Javascript可以称为lambda语言,因为所有javascript函数都具有这些属性。 They can be instantiated, aliased and passed, and don't need to have a name like functions in C do. 它们可以被实例化,别名化和传递,并且不需要像C中那样具有类似函数的名称。 So, they are anonymous, first-class functions. 所以,它们是匿名的,一流的功能。

Lambda isn't a "language" in of itself, as much as it is a part of the C# language. Lambda本身并不是一种“语言”,就像它是C#语言的一部分一样。 http://msdn.microsoft.com/en-us/library/bb397687(VS.90).aspx http://msdn.microsoft.com/en-us/library/bb397687(VS.90).aspx

Lambada expressions are "syntatic sugar" that removes a lot of redundant coding. Lambada表达式是“合成糖”,可以消除大量冗余编码。

http://www.rvenables.com/tag/lambda-expressions/ has a real good example of the shortcut lambada provides. http://www.rvenables.com/tag/lambda-expressions/有一个lambda提供的快捷方式的真实例子。

http://www.codeproject.com/KB/cs/DelegatesOMy.aspx has another example of pre/post lambda. http://www.codeproject.com/KB/cs/DelegatesOMy.aspx有另一个前/后lambda示例。

I'll have a go at your first part of your question. 我会回答你问题的第一部分。 It might be worth reposting the second & third parts as separate questions. 将第二部分和第三部分重新分配为单独的问题可能是值得的。

I like to think of lambdas in terms of being functions/procedures that I define like local variables instead of at the module level. 我喜欢将lambda视为我定义的函数/过程,就像局部变量而不是模块级别一样。

So, let's say I have this code: 所以,假设我有这个代码:

public void Run()
{
    var template = "{0} inches is {1} centimetres.";
    Console.WriteLine(template, 2.0, 2.0 * 2.54);
    Console.WriteLine(template, 5.0, 5.0 * 2.54);
}

Clearly I don't want to repeat the expression * 2.54 so I could define a function like this: 显然我不想重复表达式* 2.54所以我可以定义这样的函数:

private double Inches2Centimetres(double inches)
{
    return inches * 2.54;
}

And my code now becomes: 我的代码现在变成:

public void Run()
{
    var template = "{0} inches is {1} centimetres.";
    Console.WriteLine(template, 2.0, Inches2Centimetres(2.0));
    Console.WriteLine(template, 5.0, Inches2Centimetres(5.0));
}

But this separates the function from the calling code and, if this is the only place that I require the calculation, I'm actually hurting maintainability of my code. 但这将函数与调用代码分开,如果这是我需要计算的唯一地方,那实际上是在损害我的代码的可维护性。

I could decide to use a lambda, so I can write this instead: 我可以决定使用lambda,所以我可以写这个:

public void Run()
{
    Func<double, double> inches2Centimetres = inches => inches * 2.54;

    var template = "{0} inches is {1} centimetres.";
    Console.WriteLine(template, 2.0, inches2Centimetres(2.0));
    Console.WriteLine(template, 5.0, inches2Centimetres(5.0));
}

As far as my calling code is concerned, the difference between Inches2Centimetres & inches2Centimetres is the casing of the function name. 就我的调用代码而言, Inches2Centimetresinches2Centimetres之间的区别是函数名称的大小写。 But for code cleanliness and maintainability, the use of a lambda has given me better encapsulation. 但是为了代码清洁和可维护性,lambda的使用给了我更好的封装。

Now since the function is defined as a variable of type Func<...> you can pass lambdas around just like variables. 现在,因为函数被定义为Func<...>类型的变量,所以你可以像变量一样传递lambdas。

Here's a good example of where this can be useful: I will often create extension methods for things like database connections to hide the plumbing gumpf so as to leave the essence of the code I'm writing. 这是一个很有用的例子:我经常为数据库连接之类的东西创建扩展方法来隐藏管道gumpf,以便留下我正在编写的代码的本质。

public static T[] UsingDataReader<T>(
    this IDbConnection @this,
    string query,
    Func<IDataReader, T> transform)
{
    //...
}

The lamdba in this case, Func<IDataReader, T> transform can then be passed in when I'm calling the function and it only needs to know how to turn the current row into an object of type T . 在这种情况下,lamdba, Func<IDataReader, T> transform可以在我调用函数时传入,它只需要知道如何将当前行转换为T类型的对象。 All of the code for opening the connection, executing the reader command, moving between records and closing everything cleanly is neatly handled by the extension method. 所有用于打开连接,执行reader命令,在记录之间移动以及干净地关闭所有内容的代码都由扩展方法巧妙地处理。 My calling code is far more succinct. 我的通话代码更加简洁。

string[] names = conn.UsingDataReader<string>("select FirstName from People;",
    dr => dr["FirstName"] as string);

I know I've provided a very simplistic answer to your question, but I hope it helps. 我知道我已经为你的问题提供了一个非常简单的答案,但我希望它有所帮助。

A function in traditional Lambda calculus was a function that operates on a single value and returns a single value - a unary function. 传统Lambda演算中的函数是一个函数,它对单个值进行操作并返回单个值 - 一元函数。 They were also very simple functions that didn't do anything particularly complex (usually mapping one set to another). 它们也是非常简单的函数,它们没有做任何特别复杂的事情(通常将一组映射到另一组)。 To do complex work you would chain the functions, so that the output from a first function would be the input to a second function. 要完成复杂的工作,您可以链接函数,以便第一个函数的输出将是第二个函数的输入。

Lambdas in C# are just unary functions in the same way. C#中的Lambdas以同样的方式只是一元函数。 We use them to project, transform, filter or sort data. 我们使用它们来投影,转换,过滤或排序数据。

Think of a 'Lambda' as a function that takes on parameter and returns a value. 将'Lambda'视为一个接受参数并返回值的函数。

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

相关问题 C#进度栏-无法将其包围 - C# Progress bar - can't wrap my head around it 似乎无法在我脑海中获得WPF DataBinding - Can't seem to get WPF DataBinding in my head 我似乎无法使用C#将可为空的日期时间格式化为“ yyyy-mm-dd” - I can't seem to get my nullable datetime formatted to “yyyy-mm-dd” using C# 无法理解.NET中的后台工作者 - Can't get my head around background workers in .NET 如果我使用堆栈,我无法理解实现撤销/重做功能? - Can't get my head around implementing an Undo/Redo functionality, should I use a Stack? 我无法理解如何在 c# 中使用正则表达式或如何解决我的问题 - I cannot wrap my head around on how to use regex in c# or how to solve my problem otherwise c# 单元测试 - 似乎无法在运行时获得我的测试文件的相对路径 - c# unit test - can't seem to get a relative path to my test file at run time 似乎无法让我的asp.net C#表显示出来 - Can't seem to get my asp.net C# table to display Book Head First C# - 我无法通过关于封装的章节 - Book Head First C# - I can't get through chapter about encapsulation 我似乎无法从C#Forms应用程序调用我的Web服务 - I can't seem to call my web service from C# Forms app
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM