LINQ выберите запрос с анонимным типом и пользователем. Определенный тип
Анонимный класс имеет только свойства чтения в С#. Это часто используется для объявления в linq select query для получения определенных значений из базы данных.
В моем коде у меня есть следующий запрос. Вещь, которая путала меня, выбирая новый объект анонимного класса, используя новый оператор. У меня был класс модели StudentClerkshipsLogModel
. Когда я использую имя модели, результат запроса разрешает редактирование.
var query = (from entity in _tblStudentClerkshipsLog.GetQueryable()
where entity.StudentID == intStudentID
select new StudentClerkshipsLogModel
{
StudentClerkshipID = entity.StudentClerkshipID,
StudentID = entity.StudentID,
ClerkshipID = entity.ClerkshipID,
}).ToList();
Когда я не упоминал тип после new
в select
, я не могу выйти. компилятор вызывает ошибку. анонимный объект доступен только для чтения.
var query = (from entity in _tblStudentClerkshipsLog.GetQueryable()
where entity.StudentID == intStudentID
select new
{
StudentClerkshipID = entity.StudentClerkshipID,
StudentID = entity.StudentID,
ClerkshipID = entity.ClerkshipID,
}).ToList()
Мой вопрос в том, как linq связывает два запроса по-разному. Оба запроса имеют динамическое связывание или первый - это static.
Спасибо
Ответы
Ответ 1
Если вы правильно поняли, вам интересно, как поставщик LINQ может устанавливать свойства анонимного объекта, так как они являются "истинными" свойствами только для чтения (нет никаких private set
, но get
)?
Когда вы вызываете метод расширения Select
для IQueryable<T>
, он принимает выражение типа Expression<Func<T, TResult>
. Если вы напишете какую-нибудь заглушку для Select
, вы можете просмотреть сгенерированное выражение, используя отладчик:
public static class MyExtensions
{
public static void MySelect<T, TResult>(this IQueryable<T> query, Expression<Func<T, TResult>> projection)
{
System.Diagnostics.Debug.WriteLine(projection);
}
}
Различие заключается в том, как компилятор генерирует лямбда-выражения для именованных типов и анонимных типов. Когда вы вызываете Select
для именованного типа, выражение будет выглядеть так:
{_ => new Person() {Id = _.Id, Name = _.Name}}
То есть, во-первых, будет создан новый объект Person
, а затем члены будут инициализированы (выражение MemberInit
).
Но когда вы вызываете Select
для анонимного типа, выражение будет построено как вызов конструктора (выражение New
):
{_ => new <>f__AnonymousType0`2(a = _.Id, b = _.Name)}
Поставщик LINQ компилирует эти lambdas в делегаты, при материализации результатов запроса и в конечном итоге просто вызывает конструктор для анонимного типа.
Ответ 2
Ошибка, которую вы получаете, действительно не имеет никакого отношения к LINQ. Вы можете видеть то же самое, не используя LINQ вообще:
var anonymous = new { Name = "Fred" };
anonymous.Name = "Joe"; // Error, as properties of anonymous types are read-only
Итак, если вы хотите изменить объекты, выбранные вашим запросом LINQ, вы не должны использовать анонимные типы. Но оба запроса LINQ статически связаны - анонимные типы до сих пор полностью известны во время компиляции, а компилятор применяет к ним обычные ограничения типа. Например:
var anonymous = new { Name = "Fred" };
Console.WriteLine(anonymous.Foo); // Error: no property Foo
int bar = anonymous.Name; // Error: no conversion from string to int
Ответ 3
Я нашел следующее отличие от анонимного результата результата LINQ.
-
Результат не редактируется, например. если мы присвоим значение gridview
будут прочитаны только.
-
Проблема с областью анонимного объекта. Мы не можем передать тип к другому методу. определить параметр типа var; var всегда за которым следует выражение инициализации.
Если вам нужен результат только в текущем контексте для использования только анонимного запроса. Если вам нужен результат в другой функции, вам нужно определить тип объекта. тип объекта после new
будет создан с свойствами, которые вы хотите получить от результата define, а затем в фигурных скобках {}
.
Нет необходимости инициализировать все значения класса модели.