LINQ select query с анонимным типом и пользовательским типом

анонимный класс имеет свойства только для чтения в C#. Который часто используется для объявления в 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 заявление я не могу покинуть. компилятор поднять ошибка. enonymous объект только для чтения.

var query = (from entity in _tblStudentClerkshipsLog.GetQueryable()
             where entity.StudentID == intStudentID                             
             select new 
             {
                 StudentClerkshipID = entity.StudentClerkshipID,
                 StudentID = entity.StudentID,
                 ClerkshipID = entity.ClerkshipID,
             }).ToList()

мой вопрос в том, как linq связывает два запроса по-разному . Оба запроса имеют динамическую привязку или первый является статическим.

спасибо

3 ответов


если я правильно вас понимаю, вам интересно, как поставщик 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 компилирует эти лямбды в делегаты, при материализации результатов запроса, и в конечном итоге просто вызывает конструктор для анонимного типа.


ошибка вы получаете не имеет ничего общего с 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

Я нашел следующую разницу в результате анонимного типа результата LINQ.

  1. результат не редактируется, например, если мы назначаем значение gridview будет только чтение.

  2. проблема с областью неизвестного объекта.мы не можем пройти тип к другому методу. определите параметр типа var; var должен всегда затем следует выражение инициализации.

Если вам нужен результат только в текущем контекст только для чтения используйте анонимный запрос . Если вам нужен результат в другой функции, вы должны определить тип объекта. тип объекта после new будет создан со свойствами, которые вы хотите получить в результате определения затем в фигурных скобках {} . Нет необходимости инициализировать все значения класса model.