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

标签 c# linq anonymous-types dynamicobject

我需要将动态对象(即 List<DynamicRow> )转换为匿名类型对象列表,但我需要在运行时使用 linq 或其他方法将动态对象的所有属性创建为匿名类型对象其他方式。

这可能吗?如果是这样,我该怎么做?

这个动态对象几乎是一个网格类,其中包含一个列列表,即 List<String>和行即 List<DynamicRow> .

我可以使用列名称访问 DynamicRow 对象中保存的值(例如 Order),即 Order[<columnName>] -> Order["OrderNumber"] ,所以我希望能够使用 Linq 做同样的事情。

有没有办法循环遍历列列表并为每行创建一个匿名对象类型,其中每个属性都是根据列名称设置的。

虽然我知道下面的代码不起作用,但它可能会让我想要实现的目标更加清晰:

所以不要这样:

var itemsList = from p in customerOrderCsvReader
select new
{                            
 Item = p.ElementAt(0).Value,
 Description = p.ElementAt(1).Value,
 Comment = p.ElementAt(2).Value
};

我想要这样的东西,因为我不会提前知道项目、描述和评论等属性名称。我知道动态对象中有什么内容的唯一方法是使用列名称。

var itemsList = from p in customerOrderCsvReader
select new
{
 foreach string columnName in customerOrderCsvReader.columnNames
 {
  <columnName as property> = p.ElementAt(0).Value;
 }
};

另一个问题,假设上述是可行的,有没有办法让我使用键(即columnName而不是p.ElementAt)访问p的属性。

已更新

我可能应该更清楚。我试图将其绑定(bind)到网格,但我也试图保持这个通用性,以便它可以在任何平台上工作,而不仅仅是 winform。

如果我使用 @jjchiw 提供的代码,则在将其输出到输出窗口时会得到以下内容:

Count = 6
    [0]: {System.Dynamic.ExpandoObject}
    [1]: {System.Dynamic.ExpandoObject}
    [2]: {System.Dynamic.ExpandoObject}
    [3]: {System.Dynamic.ExpandoObject}
    [4]: {System.Dynamic.ExpandoObject}
    [5]: {System.Dynamic.ExpandoObject}

但是如果我使用 linq 并提供一些虚拟属性名称并使用如下方式为其分配一些值:

var itemsList = from p in customerOrderCsvReader
                select new
                {
                  CustomerId = p.ElementAt(0),
                  EmployerId = p.ElementAt(1),
                  Description = p.ElementAt(2)
                };

我将以下内容输出到我的输出窗口:

Count = 6
    [0]: { CustomerId = "GREAL", EmployerId = "6", Description = "1997-05-06T00:00:00" }
    [1]: { CustomerId = "HUNGC", EmployerId = "3", Description = "1997-05-06T00:00:00" }
    [2]: { CustomerId = "LAZYK", EmployerId = "8", Description = "1997-05-06T00:00:00" }
    [3]: { CustomerId = "LETSS", EmployerId = "1", Description = "1997-05-04T00:00:00" }
    [4]: { CustomerId = "WALLM", EmployerId = "5", Description = "1997-05-04T00:00:00" }
    [5]: { CustomerId = "TOTAL", EmployerId = "4", Description = "1997-05-06T00:00:00" }

将动态列表绑定(bind)到我的网格时,它不会显示任何内容,但使用匿名类型列表时(从技术上讲,匿名类型列表现在包含“可识别”对象的列表),我的网格会相应地显示数据。

是否有办法强制动态列表表现得像匿名列表,以便我可以将动态列表绑定(bind)到我的网格,但显示正确的结果。

最佳答案

创建 ExpandoObject 并转换为 IDictionary<string, object>应该做你想做的事情,像这样

var columnNames = new List<string>{"Foo", "Foo2"};
var customerOrderCsvReader = new List<List<string>>{new List<string>{"Bar", "Bar2"}};


var list = new List<dynamic>();
foreach (var element in customerOrderCsvReader)
{
    var expando = new ExpandoObject();
    var temp = (IDictionary<string, object>) expando;
    int i = 0;
    foreach(string columnName in columnNames)
    {
        temp[columnName] = element[i];
        i++;
    }
    list.Add(expando);
}

//Print Bar
Console.WriteLine (list[0].Foo);
//Print Bar2
Console.WriteLine (list[0].Foo2);

//Print Bar
Console.WriteLine ((list[0] as IDictionary<string, object>)["Foo"]);
//Print Bar2
Console.WriteLine ((list[0] as IDictionary<string, object>)["Foo2"]);

编辑。

我找到了这个库ImpromptuInterface ( nuget )我记得这个问题 也许不是您正在寻找的,因为在此解决方案中,您需要为数据网格定义接口(interface),并且您希望所有内容都是匿名的......无论如何,填充数据网格很有趣

public partial class Form1 : Form
{
    private Dictionary<string, Type> _columnTypes;

    public Form1()
    {
        InitializeComponent();

        _columnTypes = new Dictionary<string, Type>();
        _columnTypes.Add("FooFoo2", typeof(IFoo));
    }



    private void Form1_Load(object sender, EventArgs e)
    {
        var columnNames = new List<string> { "Foo", "Foo2" };
        var customerOrderCsvReader = new List<List<string>> { new List<string> { "Bar", "Bar2" } };

        var type = _columnTypes[string.Join("", columnNames)];

        var type2 = typeof(DataSourceBuilder<>).MakeGenericType(type);
        dynamic dataBuilder = Activator.CreateInstance(type2);  

        var list = dataBuilder.GetDataSource(columnNames, customerOrderCsvReader);
        dataGridView1.DataSource = list;
    }
}

public class DataSourceBuilder<T> where T : class, IDataSource
{
    public List<T> GetDataSource(List<string> columnNames, List<List<string>> customerOrderCsvReader)
    {
        var list = new List<T>();
        foreach (var element in customerOrderCsvReader)
        {
            dynamic expando = new ExpandoObject();
            var temp = (IDictionary<string, object>)expando;
            int i = 0;
            foreach (string columnName in columnNames)
            {
                temp[columnName] = element[i];
                i++;
            }
            var foo = Impromptu.ActLike<T>(temp);
            list.Add(foo);
        }

        return list;
    }
}

public interface IDataSource
{
}

public interface IFoo : IDataSource
{
    string Foo { get; set; }
    string Foo2 { get; set; }
}

关于c# - 在linq查询中设置匿名类型动态对象的所有属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19184195/

相关文章:

c# - 在构造函数中或在类的顶部创建一个对象

c# - 如何检查 DataTable 上的 IS NULL?

c# - 如何从 LINQ to SQL 中的另一个项目获取连接字符串?

dynamic - C# ‘dynamic’ 无法访问另一个程序集中声明的匿名类型的属性

C#:匿名变量的内存分配

c# - 使用应用内购买在商店中购买商品

c# - 此代码的正确 IDisposable 实现

java - 如何停止使用匿名类创建的线程?

c# - 将 IEnumerable<T> 转换/转换为 IEnumerable<U>?

c# - LINQ重构