#c_sharp #lambda
// настройка полей с помощью Fluent API modelBuilder.Entity() .Property(c => c.FirstName).IsRequired().HasMaxLength(30); modelBuilder.Entity () .Property(c => c.Email).HasMaxLength(100); modelBuilder.Entity () .Property(c => c.Photo).HasColumnType("image"); Что это вот за инструкции в коде выше? c => c.FirstName c => c.Email c => c.Photo
Ответы
Ответ 1
Конструкции вида x => x.Email (а также более сложные, вида (x, y) => x.Email + y.Age или там n => { int s = 0; while (n-- > 0) s += n * n; return s; }) — это лямбда-выражения. Они используются в C# в двух смыслах. Если в этом месте ожидается делегат/метод/что-то такое, то лямбда имеет смысл локально-определённой функции. Например, такой код: Funcf = (c => c.FirstName); по существу не отличается от кода Func f = GetFirstName; static string GetFirstName(Entity c) { return c.FirstName; } (но записывается быстрее). Кроме того (и это очень важно и удобно), лямбды могут ссылаться на локальные переменные и поля, видимые в точке определения. Например, так: int x = hey.GimmeSomeX(); Func f = n => n * x; Такого эффекта уже нельзя добиться с локальной функцией, поэтому компилятор «под капотом» использует более сложную конструкцию. Если же в месте, где упоминается лямбда, ожидается специальная штука под названием дерево выражений, то лямбда конвертируется в это самое дерево выражений. Имея дерево выражений, можно посмотреть программным путём, что же там внутри. В частности, если у вас есть c.FirstName, вы можете увидеть, что это обращение к полю с именем FirstName. Именно для этого оно используется в вашем примере. Чем же дерево выражений лучше, чем просто передать строку "FirstName"? Дело в том, что в строке вы можете ошибиться, а вот за правильностью лямбда-выражения следит компилятор. Также при переименовании IDE сможет правильно подхватить изменения. А со строкой возможны, понятно, проблемы. Ответ 2
Подобный код используется в C# для того, чтобы указать имя свойства без риска опечататься. В классическом коде это могло бы выглядеть так: modelBuilder.Entity() .Property("FirstName") .IsRequired() .HasMaxLength(30); Понятно, что при переименовании свойства FirstName код продолжает компилироваться, но перестаёт работать во время выполнения. Было бы неплохо использовать такую конструкцию, которая при переименовании свойства приводила бы к ошибке компиляции. Это давало бы нам возможность сразу обнаруживать и исправлять опечатки в названии полей. Как раз для этого и применяют синтаксис, основанный на деревьях выражений: public PrimitivePropertyConfiguration Property ( Expression > propertyExpression ) where T : struct, new() { . . . } Синтаксис страшноват, но он позволяет статически типизировать обращение к любому свойству класса. Что в данном случае происходит? Func означает, что на вход ожидается лямбда-выражение, оно же анонимная (безымянная) функция. Синтаксис таких функций в C# выглядит как x => Exp(x), где x — это параметр функции, а Exp(x) — какое-то не очень сложное выражение. В нашем случае это простое выражение — обращение к свойству объекта. Expression > означает, что мы не будем выполнять функцию непосредственно, а вместо этого построим дерево выражения и сохраним его в переменной типа Expression. Объект этого класса будет доступен во время выполнения и мы сможем пройтись по нему, и извлечь название свойства. То, что это Expression именно от Func ограничивает способ задания параметра propertyExpression: мы ждём либо имя функции с одним параметром, либо анонимную функцию с одним параметром (она же лямбда). Проще говоря, Expression > означает, что при вызове Property в качестве параметра ожидается что-то вроде x => Exp(x). Вы всё ещё можете выстрелить себе в ногу и написать неподходящее выражение, например, x => x + x, но так делать всё-таки не стоит. Наконец, в чём главная магия, как устроен метод Property? В основе, конечно, лежит рефлексия и подробности можно посмотреть в ответе на соответствующий вопрос на StackOverflow (англ.). Непосредственно в Entity Framework методы, извлекающие имя свойства из выражения, вынесены в класс ExpressionExtensions.
Комментариев нет:
Отправить комментарий