具有匿名类型和用户定义类型的 LINQ 选择查询

Posted

技术标签:

【中文标题】具有匿名类型和用户定义类型的 LINQ 选择查询【英文标题】:LINQ select query with Anonymous type and user Defined type 【发布时间】:2015-12-03 17:06:16 【问题描述】:

匿名类在 c# 中具有只读属性。这通常用于在 linq 选择查询中声明以从数据库中获取特定值。 在我的代码中,我有以下查询。让我使用新语句选择匿名类的新对象让我感到困惑的事情。我有一个模型类 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();

当我在select 语句中没有在new 之后提及类型时,我无法退出。编译器引发错误。匿名对象是只读的。

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

我的问题是 linq 如何以不同的方式绑定 about 两个查询。两个查询都有动态绑定,或者第一个是静态的。

谢谢

【问题讨论】:

“我无法退出”是什么意思?编译器抱怨什么代码? (我怀疑这是您显示的代码。)您是否稍后尝试修改对象?如果是,请显示代码。 我想稍后修改代码。但我需要知道选择查询之间的区别,以便我可以选择更好的。 @JonSkeet:看起来像是错字。 “我无法编辑”。 它们只是不同而已。一个项目为匿名类型,另一个项目为命名类型。如果你以后需要修改对象,你肯定不能使用匿名类型,因为匿名类型的属性是只读的。这与LINQ直接无关...... @MuhammadNasir:定义“更好”的标准。 【参考方案1】:

您遇到的错误实际上与 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 是如何处理的,因为查询的工作方式完全不同。我曾提到匿名对象是只读的【参考方案2】:

如果我理解正确,您想知道 LINQ 提供程序如何设置匿名对象的属性,因为它们是“真正的”只读属性(没有任何 private set,但只有 get)?

当您为IQueryable<T> 调用Select 扩展方法时,它接受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);
    

区别在于编译器如何为命名类型和匿名类型生成 lambda 表达式。当您为命名类型调用 Select 时,表达式将如下所示:

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

即首先构造新的Person对象,然后初始化成员(MemberInit表达式)。

但是当你为匿名类型调用Select时,表达式将被构建为构造函数调用(New表达式):

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

LINQ 提供程序在具体化查询结果时将这些 lambdas 编译为委托,并最终只为匿名类型调用构造函数。

【讨论】:

【参考方案3】:

我发现 LINQ 结果的匿名类型结果存在以下差异。

    结果不可编辑,例如如果我们给gridview赋值 将是只读的。

    匿名对象的范围问题。我们无法传递类型 到另一种方法。定义一个 var 类型的参数; var 必须始终 后跟一个初始化表达式。

如果您只需要当前上下文中的结果用于只读目的,请使用匿名查询。如果您需要导致其他功能,则必须定义对象类型。 new 之后的对象类型将使用您想从结果定义中获取的属性创建,然后在花括号 中。 不需要初始化模型类的所有值。

【讨论】:

以上是关于具有匿名类型和用户定义类型的 LINQ 选择查询的主要内容,如果未能解决你的问题,请参考以下文章

Linq查询返回匿名类型错误

具有匿名类型的 C# LINQ 构建表达式

LINQ查询使用GROUP BY和Count(*)进入匿名类型

C#图解教程 第十九章 LINQ

在linq查询中以匿名类型设置动态对象的所有属性

具有匿名类型模型类的剃刀视图。有可能的?