具有匿名类型和用户定义类型的 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 选择查询的主要内容,如果未能解决你的问题,请参考以下文章