【问题标题】:LINQ select query with Anonymous type and user Defined type具有匿名类型和用户定义类型的 LINQ 选择查询
【发布时间】: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:定义“更好”的标准。

标签: c# linq anonymous-class dynamic-binding


【解决方案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 结果的匿名类型结果存在以下差异。

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多