【问题标题】:Using LINQ, is it possible to output a dynamic object from a Select statement? If so, how?使用 LINQ,是否可以从 Select 语句中输出动态对象?如果是这样,怎么做?
【发布时间】:2013-03-11 09:34:45
【问题描述】:

目前在 LINQ 中,以下编译和工作正常:

var listOfFoo = myData.Select(x => new FooModel{
     someProperty = x.prop1,
     someOtherProperty = x.prop2
});

public class FooModel{
     public string someProperty  { get; set; };
     public string someOtherProperty  { get; set; };
}

但是,过去几个版本的 .NET/C# 扩展了动态对象的角色,例如 ExpandoObject,我想知道是否有办法基本上做到这一点:

var listOfFoo = myData.Select(x => new ExpandoObject{
     someProperty = x.prop1,
     someOtherProperty = x.prop2
});

显然,我已经尝试过上面的代码但没有成功,但似乎我错过了一些东西。

【问题讨论】:

  • 这里只需要简单的匿名类型投影。

标签: c# .net dynamic duck-typing expandoobject


【解决方案1】:

您应该能够在不声明任何类型的情况下创建一个新的匿名对象:

var listOfFoo = myData.Select(x => new {
    someProperty = x.prop1,
    someOtherProperty = x.prop2
});

【讨论】:

  • 天啊!伙计,我觉得很愚蠢。是的,就是这么简单。可以在 6 分钟内接受答复。谢谢!
  • @MatthewPatrickCashatt 请注意,该对象没有任何动态。这里定义的对象是静态类型的,甚至是不可变的。现在,如果这适合您的需求,那就太好了,但是如果您真的想要问题中所要求的内容,那就不是了。
  • 谢谢,@Servy。我也很欣赏你的回答。然而,关于您的评论,让我感到困惑的是@d_r_w 的方法仍然让我向对象添加动态属性。例如,foreach(dynamic item in listOfFoo{ item.someNewProperty = "bar" } 工作正常。我错过了什么?
  • @MatthewPatrickCashatt 仅仅因为它编译并不意味着它有效。使用dynamic 本质上是关闭编译器(或大部分编译器,无论如何),因此即使代码在运行时根本无法工作,您也不会出现编译时错误。
  • 作为附加说明,通过在选择匿名对象时不使用 dynamic 关键字,您可以保持编译器的类型检查,因此当您访问 someProperty 或 @ 987654326@,编译器会验证对它的所有操作是否符合属性的类型。
【解决方案2】:

没有什么可以阻止您使用Select 返回 ExpandoObject 的集合,只是您没有正确构造ExpandoObject。这是一种方法:

var listOfFoo = myData.Select(x =>
    {
        dynamic expando = new ExpandoObject();
        expando.someProperty = x.prop1;
        expando.someOtherProperty = x.prop2;
        return (ExpandoObject)expando;
    });

【讨论】:

  • 如果不转换为 IEnumerable,我认为这行不通。
  • @MystereMan 将什么转换为IEnumerable?
  • 转换 EF IQueryable(我假设它不是 Linq 到对象)。我认为 ExpandoObject 代码不能转换为 SQL,因此它可能会生成 EF 错误。您必须将结果转换为 IEnumerable 才能执行此操作。
  • @MystereMan 是什么让你认为myDataIQueryable?问题中似乎没有任何东西向我表明这一点。如果确实是IQueryable,那么是的,您需要在其中添加一个AsEnumerable 才能在客户端运行它。
  • @Todd 是的,如果您尝试将数据作为属性访问,它将不起作用,因为该对象没有该属性,它只是在使用 dynamic 时伪造它。就像我说的那样,如果您将数据作为集合中的数据访问,这就是它的本质,那么它就可以正常工作。
【解决方案3】:
using (var command = this._context.Database.GetDbConnection().CreateCommand())
        {
            command.CommandText = "select * from persons";
            command.CommandType = CommandType.Text;
            this._context.Database.OpenConnection();
            using (var result = command.ExecuteReader())
            {
                var lst = new List<object>();
                var lstColumns = new UserAccount().GetType().GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).ToList();
                while (result.Read())
                {
                    var newObject = new object();
                    dynamic myobject = new ExpandoObject();
                    IDictionary<string, object> myUnderlyingObject = myobject;
                    for (var i = 0; i < result.FieldCount; i++)
                    {
                        var name = result.GetName(i);
                        var val = result.IsDBNull(i) ? null : result[i];
                        myUnderlyingObject.Add(name, val);
                    }
                    lst.Add(myUnderlyingObject);
                }
                return Ok(lst);
            }
        }

【讨论】:

  • 这是一个非常复杂的解决方案,可以解决大约 10 年前提出并回答的一个非常简单的请求。现在要提供一个新的答案,您应该包括支持性论点,为什么该解决方案优于其他现有解决方案,但是在这里您已经回到最初的原则,用 25 行代码完成了您可以在单个 Linq 表达式中完成的事情?
  • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
  • 这是一个很好的起点。谢谢。
猜你喜欢
  • 1970-01-01
  • 2013-04-02
  • 2012-06-19
  • 1970-01-01
  • 1970-01-01
  • 2021-06-30
  • 1970-01-01
  • 2020-03-25
  • 2010-09-25
相关资源
最近更新 更多