.NET - выполнить лямбду на другом компьютере - PullRequest
1 голос
/ 06 мая 2010

Недавно я реализовал приложение веб-службы IronRuby для клиента, чтобы заменить существующую C # .NET DLL. Что клиент забыл упомянуть, так это то, что тем временем он внедрил новую версию DLL с новым API на основе лямбда-выражений. И удостоверился, что все вызовы (тысячи :() используют новый синтаксис. Поэтому теперь мне нужно реализовать замену .NET DLL, которая получает Func / Actions и выполняет их на удаленном сервере.

Теперь я парень по Ruby / Perl и мало знаком с продвинутым .NET. Я не совсем понимаю разницу между выражениями и лямбами. Я знаю, что LINQ to SQL может выполнять выражения на удаленном сервере SQL. Может ли он выполнять лямбды тоже? Могу ли я использовать тот же подход (какой бы он ни был) в моем сценарии?

Как правило, любые указатели / идеи / решения приветствуются.

Спасибо, Фредерик

1 Ответ

2 голосов
/ 14 июля 2010

Я не уверен точно, что вы просите; но, по крайней мере, я могу попытаться дать некоторое представление о разнице между Expression и лямбда-функциями, которые являются языковыми особенностями основных языков .NET (C #, VB.NET).


По существу, лямбда-функция - это анонимная (неназванная) функция, которая может быть объявлена ​​внутри области действия другой функции. В C # (языковая версия 3) это будет объявлено так:

( список параметров ) => тело функции

Например:

void Foo()
{
    // two equivalent lambda functions with one double parameter 'x' each:
    var square = (double x) => x * x;
    var square2 = (double x) => { return x * x; };

    // lambda function that doesn't take any arguments:
    var doSomething = () => { Console.WriteLine("Hello."); }
}

(обратите внимание, что, например, square - это не имя лямбда-функции, а переменная, которая на нее ссылается. Сама лямбда-функция не имеет никакого имени, как у метода void Foo()!)

Нечто очень похожее уже было возможно в C # версии 2, называемой анонимными делегатами :

delegate(double x) { return x * x; }  // is equivalent to: (double x) => x * x

Выражения были добавлены в .NET с LINQ (в пространстве имен System.Linq.Expressions). По сути, это простые структуры данных, которые описывают, как абстрактное синтаксическое дерево (AST), любые вычисления, которые могут быть выражены, например. с C # или VB.NET. Взять например:

// case 1. IEnumerable<int>:
IEnumerable<int> xs = ...;
IEnumerable<int> queryXs = from x in xs where x > 0 select x;

// case 2. IQueryable<int>:
IQueryable<int>  ys = ...;
IEnumerable<int> queryYs = from y in ys where y > 0 select y;

Эти два запроса идентичны, за исключением того, что ys имеет тип IQueryable<int> вместо IEnumerable<int>. Компилятор C # переведет вышеупомянутые два запроса в другой код, а именно:

// case 1. IEnumerable<int>:
IQueryable<int> xs = ...;
IEnumerable<int> queryXs = xs.Where<int>(delegate (int x) { return x > 0; });

// case 2. IQueryable<int>:
IEnumerable<int> ys = ...;
ParameterExpression yParameter = Expression.Parameter(typeof(int), "y");
IEnumerable<int> queryYs.Where<int>(
    Expression.Lambda<Func<int, bool>>(
        Expression.GreaterThan(
            yParameter,
            Expression.Constant(0, typeof(int))),
        new ParameterExpression[] { yParameter }));

Если вы изучите последнее, вы увидите, что для запроса IQueryable<int> компилятор вывел проанализированный запрос в виде структуры данных, которая описывает запрос. С другой стороны, для запроса к IEnumerable<int> он просто выводит код, который выполняет запрос. Оказывается, что компилятор делает особую магию, создавая то, что он анализировал как дерево выражений только с типом IQueryable<T>.

Таким образом,

Expressions и IQueryable<T> позволяют анализировать запрос во время выполнения и выполнять его оптимизацию и другие преобразования перед его фактическим выполнением. Это интенсивно используется, например, LINQ to SQL для написания интеллектуальных, оптимизированных SQL-запросов:

Представьте, что в базе данных запрашиваются все строки, в которых столбец x равен> 0.

  • Если бы база данных была IEnumerable<int> (это действительно сильно упрощает, я знаю, но терпите меня), все строки должны быть извлечены, а затем отфильтрованы методом .Where(delegate (int x) { ... }).

  • Если база данных была IQueryable<int>, вывод Expression компилятором будет проанализирован и преобразован в SQL-запрос во время выполнения, так что он будет включать соответствующее предложение WHERE x > 0 и будет производить только нужные строки сразу.


Если вас интересует внутренняя структура / синтаксический анализ деревьев выражений, взгляните на серию подробных блогов Барта де Смета, начиная с Сказки IQueryable - LINQ to LDAP - Часть 0: Введение .

...