Search code examples
c#linqanonymous-classdynamic-binding

LINQ select query with Anonymous type and user Defined type


Anonymous class has read only properties in c#. Which is often used to to declare in linq select query to get particular values from database. In my code I have the following query.The thing that confused me selecting new object of anonymous class using new statement. I had a model class of StudentClerkshipsLogModel . When I Use model name the query result allow editing.

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

When I did not mention type after new in select statement I am unable to exit. compiler raise an error . enonymous object is read only.

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

my question is how linq bind the about two query differently . Both queries have dynamic binding or first one is is static.

Thanks


Solution

  • If I understand you correctly, you're wondering, how LINQ provider can set properties of anonymous object, since they are "true" read only properties (there's no any private set, but get only)?

    When you call Select extension method for IQueryable<T>, it accepts an expression of type Expression<Func<T, TResult>. If you'll write some stub for Select you can look into the generated expression, using debugger:

    public static class MyExtensions
    {
        public static void MySelect<T, TResult>(this IQueryable<T> query, Expression<Func<T, TResult>> projection)
        {
            System.Diagnostics.Debug.WriteLine(projection);
        }
    }
    

    The difference is in how compiler generates lambda expressions for named types and anonymous types. When you call Select for named type, expression will look like this:

    {_ => new Person() {Id = _.Id, Name = _.Name}}
    

    That is, firstly new Person object will be constructed, and then members will be initialized (MemberInit expression).

    But when you call Select for anonymous type, expression will be built as constructor call (New expression):

    {_ => new <>f__AnonymousType0`2(a = _.Id, b = _.Name)}
    

    LINQ provider compiles these lambdas into delegates, when materializing query results, and ultimately just calls constructor for anonymous type.