คำหลักตัวแทนกับสัญลัมแลมบ์ดา


คำตอบ:


140

คำตอบสั้น ๆ : ไม่

คำตอบอีกต่อไปที่อาจไม่เกี่ยวข้อง:

  • หากคุณกำหนดแลมบ์ดาให้กับประเภทผู้ร่วมประชุม (เช่นFuncหรือAction) คุณจะได้รับผู้แทนแบบไม่ระบุชื่อ
  • หากคุณกำหนดแลมบ์ดาให้กับประเภท Expression คุณจะได้รับแผนภูมินิพจน์แทนตัวแทนที่ไม่ระบุชื่อ ทรีนิพจน์สามารถถูกคอมไพล์ไปยังผู้รับมอบสิทธิ์ที่ไม่ระบุชื่อ

แก้ไข: นี่คือลิงค์สำหรับ Expressions

  • System.Linq.Expression.Expression (TDelegate) (เริ่มต้นที่นี่)
  • Linq ในหน่วยความจำกับผู้แทน (เช่น System.Func) ใช้System.Linq.Enumerable Linq เพื่อ SQL (และสิ่งอื่น ๆ ) ที่มีการแสดงออกใช้System.Linq.Queryable ตรวจสอบพารามิเตอร์ของวิธีการเหล่านั้น
  • ชี้แจงจาก ScottGu โดยสรุป Linq ในหน่วยความจำจะสร้างวิธีที่ไม่ระบุชื่อเพื่อแก้ไขข้อสงสัยของคุณ Linq เป็น SQL จะสร้างแผนภูมินิพจน์ที่แสดงถึงคิวรีจากนั้นแปลทรีนั้นเป็น T-SQL Linq to Entities จะสร้างแผนภูมินิพจน์ที่แสดงถึงคิวรีจากนั้นแปลทรีนั้นเป็นแพลตฟอร์ม SQL ที่เหมาะสม

3
ประเภทนิพจน์หรือไม่ ฟังดูเหมือนอาณาเขตใหม่สำหรับฉัน ฉันจะหาข้อมูลเพิ่มเติมเกี่ยวกับประเภท Expression และการใช้ต้นไม้แสดงออกใน C # ได้ที่ไหน
MojoFilter

2
คำตอบที่ได้อีกต่อไป - มีเหตุผลเที่ยวยุ่งยิ่งทำไมพวกเขากำลังแปลงสภาพให้แก่ผู้ร่วมประชุมประเภทที่แตกต่างกันมากเกินไป :)
จอนสกีต

โปรดทราบว่าแลมบ์ดาสามารถกำหนดให้กับประเภท Expression เท่านั้นหากเป็นแลมบ์ดานิพจน์
Micha Wiedenmann

125

ฉันชอบคำตอบของ Amy แต่ฉันคิดว่าฉันอวดความสามารถ คำถามบอกว่า "เมื่อรวบรวมแล้ว" - ซึ่งแสดงให้เห็นว่าทั้งสองสำนวนได้รับการรวบรวม พวกเขาจะรวบรวมได้อย่างไร แต่มีใครถูกเปลี่ยนให้เป็นผู้รับมอบสิทธิ์และอีกคนหนึ่งเป็นต้นไม้แสดงออก? มันเป็นเรื่องยาก - คุณต้องใช้คุณสมบัติอื่นของวิธีการที่ไม่ระบุชื่อ อันเดียวที่ไม่ได้แบ่งปันโดยการแสดงออกแลมบ์ดา หากคุณระบุวิธีที่ไม่ระบุชื่อโดยไม่ได้ระบุรายการพารามิเตอร์เลยมันจะเข้ากันได้กับประเภทตัวแทนที่ส่งคืนเป็นโมฆะและไม่มีoutพารามิเตอร์ใด ๆ ด้วยความรู้นี้เราควรจะสามารถสร้างสองเกินพิกัดเพื่อให้การแสดงออกอย่างสมบูรณ์โปร่งใส แต่แตกต่างกันมาก

แต่เกิดภัยพิบัติ! อย่างน้อยด้วย C # 3.0 คุณไม่สามารถแปลงนิพจน์แลมบ์ดาที่มีเนื้อความบล็อกเป็นนิพจน์ได้และคุณไม่สามารถแปลงนิพจน์แลมบ์ดาด้วยการกำหนดค่าในร่างกาย (แม้ว่าจะใช้เป็นค่าส่งคืน) สิ่งนี้อาจเปลี่ยนแปลงด้วย C # 4.0 และ. NET 4.0 ซึ่งอนุญาตให้แสดงได้มากขึ้นในทรีนิพจน์ ดังนั้นในคำอื่น ๆ ที่มีตัวอย่าง MojoFilter ที่เกิดขึ้นเพื่อให้ทั้งสองจะเกือบเสมอถูกแปลงเป็นสิ่งเดียวกัน (รายละเอียดเพิ่มเติมในหนึ่งนาที)

เราสามารถใช้เคล็ดลับพารามิเตอร์ผู้มอบหมายหากเราเปลี่ยนร่างกายเล็กน้อย:

using System;
using System.Linq.Expressions;

public class Test
{
    static void Main()
    {
        int x = 0;
        Foo( () => x );
        Foo( delegate { return x; } );
    }

    static void Foo(Func<int, int> action)
    {
        Console.WriteLine("I suspect the anonymous method...");
    }

    static void Foo(Expression<Func<int>> func)
    {
        Console.WriteLine("I suspect the lambda expression...");
    }
}

แต่เดี๋ยวก่อน! เราสามารถแยกความแตกต่างระหว่างทั้งสองได้โดยไม่ต้องใช้ต้นไม้แสดงออกถ้าเราฉลาดแกมโกงมากพอ ตัวอย่างด้านล่างใช้กฎการแก้ปัญหาการโอเวอร์โหลด (และเคล็ดลับการจับคู่ผู้ร่วมประชุมโดยไม่ระบุชื่อ) ...

using System;
using System.Linq.Expressions;

public class Base
{
    public void Foo(Action action)
    {
        Console.WriteLine("I suspect the lambda expression...");
    }
}

public class Derived : Base
{
    public void Foo(Action<int> action)
    {
        Console.WriteLine("I suspect the anonymous method...");
    }
}

class Test
{
    static void Main()
    {
        Derived d = new Derived();
        int x = 0;
        d.Foo( () => { x = 0; } );
        d.Foo( delegate { x = 0; } );
    }
}

อุ๊ยตาย จำเด็ก ๆ ทุกครั้งที่คุณใช้วิธีมากไปจากคลาสพื้นฐานลูกแมวตัวน้อยจะเริ่มร้องไห้


9
ฉันออกจากข้าวโพดคั่วแล้วอ่านทั้งหมด นั่นคือความแตกต่างที่ฉันอาจจะไม่เคยคิดเลยแม้ว่าฉันจะจ้องมองที่หน้า
MojoFilter

27
ฉันรู้เรื่องนี้บ้าง แต่ฉันต้องแสดงความยินดีกับความสามารถของคุณในการสื่อสารกับมนุษย์
เอมี่ B

1
สำหรับใครที่สนใจในการเปลี่ยนแปลงใน .NET 4.0 (ขึ้นอยู่กับ CTP) - กำหนดดูmarcgravell.blogspot.com/2008/11/future-expressions.html โปรดทราบว่า C # 4.0 ยังไม่ได้ทำอะไรใหม่ ๆ เท่าที่ฉันสามารถบอกได้
Marc Gravell

4
จอนคุณร็อค Erik เพื่อที่จะเป็นแฟนพันธุ์แท้ Skeet จริง ๆ คุณควรสมัครเป็นสมาชิกกับกองซ้อนของเขาอย่างที่ฉันเป็น เพียงติดstackoverflow.com/users/22656ในโปรแกรมอ่านฟีดของคุณ
Paul Batum

3
@RoyiNamir: หากคุณใช้วิธีการแบบไม่ระบุชื่อโดยไม่มีรายการพารามิเตอร์นั่นเข้ากันได้กับประเภทผู้รับมอบสิทธิ์ใด ๆ ที่มีพารามิเตอร์ที่ไม่อ้างอิง / ออกตราบใดที่ประเภทการคืนค่าเข้ากันได้ โดยทั่วไปคุณกำลังพูดว่า "ฉันไม่สนใจเกี่ยวกับพารามิเตอร์" ทราบว่าdelegate { ... }เป็นไม่ได้เช่นเดียวกับdelegate() { ... }- หลังเป็นเพียงเข้ากันได้กับประเภท parameterless ผู้ร่วมประชุม
Jon Skeet

2

ในสองตัวอย่างข้างต้นไม่มีความแตกต่างศูนย์

การแสดงออก:

() => { x = 0 }

เป็นนิพจน์แลมบ์ดาที่มีเนื้อหาคำสั่งดังนั้นจึงไม่สามารถรวบรวมเป็นต้นไม้การแสดงออกได้ ในความเป็นจริงมันไม่ได้คอมไพล์เพราะมันต้องการอัฒภาคหลังจาก 0:

() => { x = 0; } // Lambda statement body
() => x = 0      // Lambda expression body, could be an expression tree. 

6
แน่นอนว่าหมายถึงมีความแตกต่างของ "ใครจะรวบรวมคนอื่น ๆ จะไม่";)
จอนสกีต

2

Amy B ถูกต้อง โปรดทราบว่าอาจมีข้อได้เปรียบในการใช้ทรีนิพจน์ LINQ ไปยัง SQL จะตรวจสอบแผนผังนิพจน์และแปลงเป็น SQL

นอกจากนี้คุณยังสามารถเล่นลูกเล่นกับ lamdas และ tree expression เพื่อส่งชื่อของสมาชิกคลาสไปยังเฟรมเวิร์กได้อย่างมีประสิทธิภาพด้วยวิธีที่ปลอดภัย Moqเป็นตัวอย่างของสิ่งนี้


-1

มีความแตกต่าง

ตัวอย่าง:

var mytask = Task.Factory.StartNew(() =>
{
    Thread.Sleep(5000);
    return 2712;
});
mytask.ContinueWith(delegate
{
    _backgroundTask.ContinueTask(() =>lblPercent.Content = mytask.Result.ToString(CultureInfo.InvariantCulture));
});   

และฉันแทนที่ด้วยแลมบ์ดา: (ผิดพลาด)

var mytask = Task.Factory.StartNew(() =>
{
    Thread.Sleep(5000);
    return 2712;
});
mytask.ContinueWith(()=>
{
    _backgroundTask.ContinueTask(() =>lblPercent.Content = mytask.Result.ToString(CultureInfo.InvariantCulture));
});

ผิดแลมบ์ดาผิดพลาดเพียงเพราะลายเซ็นพารามิเตอร์เมธอดไม่ตรงกัน
Jack Wang

-1

พื้นฐานบางอย่างที่นี่

นี่เป็นวิธีที่ไม่ระบุชื่อ

(string testString) => { Console.WriteLine(testString); };

เนื่องจากวิธีการที่ไม่ระบุชื่อไม่มีชื่อเราจึงต้องมีผู้รับมอบสิทธิ์ซึ่งเราสามารถกำหนดวิธีหรือนิพจน์เหล่านี้ได้ เช่น

delegate void PrintTestString(string testString); // declare a delegate

PrintTestString print = (string testString) => { Console.WriteLine(testString); }; 
print();

เช่นเดียวกันกับการแสดงออกแลมบ์ดา โดยปกติแล้วเราต้องการผู้ร่วมงานเพื่อใช้พวกเขา

s => s.Age > someValue && s.Age < someValue    // will return true/false

เราสามารถใช้ตัวแทน func เพื่อใช้การแสดงออกนี้

Func< Student,bool> checkStudentAge = s => s.Age > someValue && s.Age < someValue ;

bool result = checkStudentAge ( Student Object);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.