słowo kluczowe delegata a notacja lambda

Po skompilowaniu jest różnica między:

delegate { x = 0; }

I

() => { x = 0 }

?

Author: abatishchev, 2008-11-18

6 answers

Krótka odpowiedź: Nie.

Dłuższa odpowiedź, która może nie być istotna:

  • jeśli przypiszesz lambda do typu delegata (np. Func LUB Action), Otrzymasz anonimowego delegata.
  • jeśli przypiszesz lambda do typu wyrażenia, otrzymasz drzewo wyrażeń zamiast anonimowego delegata. Drzewo wyrażeń może być następnie skompilowane do anonimowego delegata.

Edytuj: Oto kilka linków do Wyrażenia.

  • System.Linq.Ekspresja.Expression (TDelegate) (start tutaj).
  • Linq w pamięci z delegatami (np. System.Func) używa systemu .Linq.Enumerable . Linq do SQL (i wszystkiego innego) z wyrażeniami używa systemu .Linq.Queryable . Sprawdź parametry tych metod.
  • An Wyjaśnienie ScottGu . W skrócie, Linq in-memory stworzy anonimowe metody rozwiązywania zapytań. LINQ do SQL będzie Utwórz drzewo wyrażeń, które reprezentuje zapytanie, a następnie Przetłumacz to drzewo do T-SQL. Linq to Entities wytworzy drzewo wyrażeń, które reprezentuje zapytanie, a następnie przełoży je na odpowiedni dla platformy SQL.
 141
Author: Amy B,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-26 12:39:57

Podoba mi się odpowiedź Amy, ale myślałem, że będę pedantyczny. Pytanie mówi, "raz jest skompilowany" - co sugeruje, że oba wyrażenia zostały skompilowane. W jaki sposób mogą się skompilować, ale jeden z nich jest konwertowany do delegata, a drugi do drzewa wyrażeń? Jest to trudne - trzeba użyć innej funkcji metod anonimowych, jedynej, której nie współdzielą wyrażenia lambda. Jeśli podasz metodę anonimową bez podawania listy parametrów w ogóle to jest kompatybilny z dowolnym typem delegata zwracającym void i bez żadnych parametrów out. Uzbrojeni w tę wiedzę, powinniśmy być w stanie skonstruować dwa przeciążenia, aby wyrażenia były całkowicie jednoznaczne, ale bardzo różne.

Ale katastrofa uderza! Przynajmniej w C# 3.0, nie można przekonwertować wyrażenia lambda z ciałem bloku na wyrażenie - nie można też przekonwertować wyrażenia lambda z przypisaniem w ciele (nawet jeśli jest ono używane jako wartość zwracana). Może się to zmienić w C # 4.0 i . NET 4.0, które pozwalają na więcej wyrażeń w drzewie wyrażeń. Innymi słowy, z przykładami, które podał MojoFilter, oba będą prawie zawsze będą konwertowane do tego samego. (Więcej szczegółów za chwilę.)

Możemy użyć sztuczki z parametrami delegata, jeśli zmienimy trochę ciała:

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...");
    }
}
Ale czekaj! Możemy rozróżnić te dwa, nawet bez użycia drzew wyrażeń, jeśli jesteśmy wystarczająco sprytni. Poniższy przykład wykorzystuje przeciążenie zasady rozstrzygania sporów (oraz trik dopasowywania anonimowych delegatów)...
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; } );
    }
}
AUĆ. Pamiętajcie dzieci, za każdym razem, gdy przeciążacie metodę odziedziczoną po klasie podstawowej, mały kotek zaczyna płakać.
 125
Author: Jon Skeet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-11-06 18:28:55

W dwóch powyższych przykładach nie ma różnicy, zero.

Wyrażenie:

() => { x = 0 }

Jest wyrażeniem Lambda z ciałem instrukcji, więc nie może być skompilowane jako drzewo wyrażeń. W rzeczywistości nie kompiluje się, ponieważ potrzebuje średnika po 0:

() => { x = 0; } // Lambda statement body
() => x = 0      // Lambda expression body, could be an expression tree. 
 2
Author: Olmo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-24 17:28:24

Amy B ma rację. Zauważ, że używanie drzew wyrażeń może być korzystne. LINQ to SQL sprawdzi drzewo wyrażeń i przekonwertuje je na SQL.

Możesz również wykonywać sztuczki z lamdami i drzewami wyrażeń, aby skutecznie przekazać nazwy członków klasy do frameworka w bezpieczny dla refaktoryzacji sposób. Moq jest tego przykładem.

 2
Author: Daniel Plaisted,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-09-07 04:24:42

Istnieje różnica

Przykład:

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

I zamieniam na lambda: (błąd)

var mytask = Task.Factory.StartNew(() =>
{
    Thread.Sleep(5000);
    return 2712;
});
mytask.ContinueWith(()=>
{
    _backgroundTask.ContinueTask(() =>lblPercent.Content = mytask.Result.ToString(CultureInfo.InvariantCulture));
});
 -1
Author: Án Bình Trọng,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-03 07:54:29

Kilka podstaw tutaj.

Jest to metoda anonimowa

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

Ponieważ Metody anonimowe nie mają nazw, potrzebujemy delegata, do którego możemy przypisać obie te metody lub wyrażenia. np.

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

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

To samo dotyczy wyrażenia lambda. Zazwyczaj potrzebujemy delegata do ich użycia
s => s.Age > someValue && s.Age < someValue    // will return true/false

Możemy użyć delegata func do użycia tego wyrażenia.

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

bool result = checkStudentAge ( Student Object);
 -1
Author: Yogesh Prajapati,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-04-26 00:46:39