delegate anahtar kelimesi veya lambda gösterimi


Yanıtlar:


140

Kısa cevap: hayır.

Alakalı olmayan daha uzun cevap:

  • Lambda'yı bir delege türüne ( Funcveya gibi Action) atarsanız, anonim bir temsilci alırsınız.
  • Lambda'yı bir İfade türüne atarsanız, anonim bir temsilci yerine bir ifade ağacı alırsınız. İfade ağacı daha sonra anonim bir delege olarak derlenebilir.

Düzenleme: İşte İfadeler için bazı bağlantılar.

  • System.Linq.Expression.Expression (TDelegate) (buradan başlayın).
  • Temsilcilerle Linq bellek içi (System.Func gibi) System.Linq.Enumerable kullanır . Linq to SQL (ve başka bir şey) ifadeleri ile System.Linq.Queryable kullanır . Bu yöntemlerde parametreleri kontrol edin.
  • ScottGu'dan bir açıklama . Özetle, Linq in-memory sorgunuzu çözmek için bazı anonim yöntemler üretecektir. Linq to SQL, sorguyu temsil eden bir ifade ağacı üretecek ve daha sonra bu ağacı T-SQL'e çevirecektir. Linq to Entities, sorguyu temsil eden bir ifade ağacı üretecek ve daha sonra bu ağacı platforma uygun SQL'e çevirecektir.

3
Bir İfade türü mü? Bu bana yeni bir bölge gibi geliyor. İfade türleri ve C # 'da ifade ağaçları kullanma hakkında daha fazla bilgiyi nerede bulabilirim?
MojoFilter

2
Daha uzun cevap - farklı delege türlerine de dönüştürülebilir olmalarının nedenleri var :)
Jon Skeet

Lambda'nın yalnızca bir ifade lambda olması durumunda bir İfade türüne atanabileceğini unutmayın.
Micha Wiedenmann

125

Amy'nin cevabını seviyorum ama bilgiçlik yapacağımı düşündüm. Soru, "Bir kez derlendi" der - bu da her iki ifadenin de derlendiğini gösterir. Her ikisi de nasıl derlenebilir, ancak biri delege, diğeri de ifade ağacına dönüştürülürse? Bu zor bir şey - anonim yöntemlerin başka bir özelliğini kullanmanız gerekir; lambda ifadeleri tarafından paylaşılmayan tek kişi. Eğer parametre listesine belirtmeden anonim yöntemi belirtirseniz hiç herhangi temsilci türü boş dönen ve herhangi olmadan uyumludur outparametreler. Bu bilgiyle donanmış olarak, ifadeleri tamamen açık ama çok farklı hale getirmek için iki aşırı yük inşa edebilmeliyiz.

Ama felaketler! En azından C # 3.0 ile, blok gövdeli bir lambda ifadesini bir ifadeye dönüştüremezsiniz - veya bir lambda ifadesini gövdede bir atamayla (dönüş değeri olarak kullanılsa bile) dönüştüremezsiniz. Bu, bir ifade ağacında daha fazlasının ifade edilmesine izin veren C # 4.0 ve .NET 4.0 ile değişebilir. Başka bir deyişle, MojoFilter'in verdiği örneklerle, ikisi neredeyse her zaman aynı şeye dönüştürülecek. (Bir dakika içinde daha fazla ayrıntı.)

Cesetleri biraz değiştirirsek delege parametrelerini kullanabiliriz:

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...");
    }
}

Fakat bekle! Eğer yeterince kurnazsak, ifade ağaçları kullanmadan bile bu ikisi arasında ayrım yapabiliriz. Aşağıdaki örnekte aşırı yük çözünürlüğü kuralları (ve anonim delege eşleştirme hilesi) kullanılmıştır ...

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; } );
    }
}

Ahh. Çocukları hatırlayın, bir temel sınıftan miras alınan bir yöntemi her aşırı yüklediğinizde, küçük bir yavru kedi ağlamaya başlar.


9
Patlamış mısırımı çıkardım ve her şeyi okudum. Bu, yüzüne doğru baksa bile muhtemelen asla düşünmeyeceğim bir ayrım.
18:40

27
Bunlardan bazılarını biliyordum, ama sizi insanlarla iletişim kurabildiğiniz için sizi tebrik etmeliyim.
Amy B

1
.NET 4.0'daki (CTP tabanlı) değişikliklerle ilgilenen herkes için - bkz. Marcgravell.blogspot.com/2008/11/future-expressions.html . C # 4.0'ın anlayabildiğim kadarıyla yeni bir şey yapmadığını unutmayın.
Marc Gravell

4
Jon, sen sallan. Erik, gerçek bir Skeet fanboi olmak için, benim gibi yığın taşması rss'e abone olmalısınız. Stackoverflow.com/users/22656 adresini feed okuyucunuza yapıştırmanız yeterlidir.
Paul Batum

3
@RoyiNamir: Parametre listesi olmadan anonim bir yöntem kullanırsanız , geri dönüş tipi uyumlu olduğu sürece ref / out parametreleri olmayan herhangi bir delege türü ile uyumludur. Temelde "Parametreler umurumda değil" diyorsunuz. Not delegate { ... }olduğu değil aynı delegate() { ... }ikincisi parametresiz temsilci türü ile uyumludur -.
Jon Skeet

2

Yukarıdaki iki örnekte hiçbir fark yoktur, sıfır.

İfade:

() => { x = 0 }

ifade gövdesine sahip bir Lambda ifadesidir, bu nedenle bir ifade ağacı olarak derlenemez. Aslında derlenmez, çünkü 0'dan sonra noktalı virgül gerekir:

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

6
Elbette ki bu "biri derlenecek, diğeri olmayacak" arasında bir fark olduğu anlamına gelir;)
Jon Skeet

2

Amy B doğru. İfade ağaçlarını kullanmanın avantajları olabileceğini unutmayın. LINQ to SQL, ifade ağacını inceler ve SQL'e dönüştürür.

Ayrıca sınıf üyelerinin adlarını yeniden düzenleme-güvenli bir şekilde bir çerçeveye etkili bir şekilde aktarmak için lamdalar ve ifade ağaçları ile hileler oynayabilirsiniz. Adedi bunun bir örneğidir.


-1

Bir fark var

Misal:

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

Ve lambda ile değiştiriyorum: (hata)

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

Yanlış ~ lambda, yöntem parametre imzası eşleşmediğinden başarısız oldu.
Jack Wang

-1

Burada bazı temel bilgiler.

Bu anonim bir yöntemdir

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

Anonim yöntemlerin isimleri olmadığından, bu yöntemlerin veya ifadelerin her ikisini de atayabileceğimiz bir temsilciye ihtiyacımız var. Örneğin

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

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

Lambda ifadesi ile aynı. Genellikle onları kullanmak için bir temsilciye ihtiyacımız var

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

Bu ifadeyi kullanmak için bir işlev temsilcisi kullanabiliriz.

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

bool result = checkStudentAge ( Student Object);
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.