Lambda的使用让我感到困惑

4

我正在按照一本书的内容实现一个项目,但是我对于为什么需要使用这些lambda函数感到有些困惑。

public class Cart
{
    private List<CartLine> lineCollection = new List<CartLine>();
    public class CartLine
    {
        public Product Product { get; set; }
        public int Quantity { get; set; }
    }
    public void RemoveLine(Product product)  
    {
        lineCollection
          .RemoveAll(p => p.Product.ProductID == product.ProductID);
    }
}

为什么我需要使用.RemoveAll(p=> p.Product.ProductID == product.ProductID)? 这与.RemoveAll只需要一个lambda表达式有关吗?我不确定为什么我不能使用this.Product.ProductID,我意识到Product是一个列表,p=> P.Product是否在做一些迭代并比较值直到找到它所需的内容?

Product在以下位置被定义

public class Product
{
    public int ProductID { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public decimal Price { get; set; }
    public string Category { get; set; }
}

我通常对这种情况下Lambda的目的感到困惑。是否有相当于p=>p.Product.ProductID == product.ProductID的东西?我可以不使用Lambda来更好地理解它的缩写吗?我似乎无法理解这个问题,提前感谢您的帮助。
5个回答

6

它们是代理的简写。在您的情况下,没有 lambda 表达式的相同代码将如下所示:

    public void RemoveLine( Product product )
    {
        var helper = new RemoveAllHelper();
        helper.product = product;

        lineCollection.RemoveAll( helper.TheMethod );
    }

    class RemoveAllHelper
    {
        public Product product;
        public bool TheMethod( CartLine p ) { return p.Product.ProductID == product.ProductID; }
    }

由于您的lambda包含一个在lambda之外定义的变量(称为“绑定”或“捕获”变量),编译器必须创建一个带有字段的辅助对象,以将该变量放入其中。

对于没有绑定变量的lambda,可以使用静态方法:

    public void RemoveLine( Product product )
    {
        lineCollection.RemoveAll( TheMethod );
    }

    public static bool TheMethod( CartLine p ) { return p.Product.ProductID == 5; }

当唯一的绑定变量是this时,可以利用同一对象上的实例方法:

    public void RemoveLine( Product product )
    {
        lineCollection.RemoveAll( this.TheMethod );
    }

    public bool TheMethod( CartLine p ) { return p.Product.ProductID == this.targetProductID; }

1
请注意,Lambda表达式在需要时会转换为委托(如此情况),但如果上下文需要,它也可以是表达式树。- http://msdn.microsoft.com/en-us/library/bb397687.aspx。 - Alexei Levenkov
2
@AlexeiLevenkov:不要一开始就添加不必要的复杂性。让提问者逐步学习。 - Fyodor Soikin

2

下载Resharper的试用版,只需按下alt-enter并选择您想要的选项即可将lambda表达式转换为委托或命名函数等。这有助于我理解各种内容。


2

RemoveAll 的实现有一种迭代器,它在每次迭代时调用您的匿名函数。例如:

iterator {
    your_lambda_function(current_item);
}

p => p.Product.ProductID == product.ProductID可以改写为:

delegate(CartLine p) { return p.Product.ProductID == product.ProductID; }

这可能对您来说更加清晰。


啊,那样做确实很有道理。所以一些这样的实现包含迭代器,而您正在传递一种解决每个项目的方法。 我理解在迭代器中传递函数来解决从哪里构建集合的问题,然后请问一个问题, 我猜并不是所有这些 Linq 东西都包含迭代器。我看到在另一个类 [这是在产品中] .OrderBy(p=> p.ProductID) 我有点困惑,因为它不像是使用 ProductID 来解决某个集合,而是以某种标准使用它?它是否只作为对 ProductID 的引用? - Jordan
1
@Jordan:不是的,在OrderBy示例中,你只需传递一个lambda表达式,该表达式将用于返回集合用于排序的值。你可以传递p => generate-random-value并每次获得随机排序。因此,它不是对ProductID的引用,而只是一些值。 - zerkms

1

不需要使用Lambda表达式。你同样可以用实现相同签名的方法名称来替换它们。


1

你也可以像普通的一样删除它们。

public void RemoveLine(Product product) {
    for (var i = 0; i < lineCollection.Count;) {
        if (lineCollection[i].Product.ProductID == product.ProductID) {
            lineCollection.RemoveAt(i);
        } else { ++i; }
    }
}

我认为lambda更好。实际上,看一下这段代码就可以证明使用函数对象(无论是lambda还是命名函数)可以使代码更易于理解。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接