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, а затем в фигурных скобках {}. Нет необходимости инициализировать все значения класса модели.