【问题标题】:Dynamically create anonymous object from list values c#从列表值动态创建匿名对象c#
【发布时间】:2014-08-19 06:25:33
【问题描述】:

我有一个字符串列表(或者可以是数组),我想从中动态创建一个匿名对象。我该怎么做?

var dataSet = new DataSet();
dataSet.ReadXml(@"");
var dataTable = dataSet.Tables[0];
var dataRow = dataTable.Rows[0];    

var keys = new List<string> {"Column1","Column2"};
var result = new {keys[0] = dataRow[keys[0]], keys[1] = dataRow[keys[1]]}

因此,将在此方法之外创建名为“keys”的列表,并且可以包含 1 到多个值。我尝试创建一个字典并遍历列表并将键/值对添加到字典中,但后来我不知道如何将字典转换回匿名类型。我还尝试了 expando 对象,但这似乎并没有让我走得更远。

我必须能够返回一个匿名类型,因为此方法的结果将与 LINQ 查询的 GroupBy 子句一起使用。

这是我必须动态创建字典的方法:

    public object Key(DataRow dataRow, List<String> keys)
    {
        var dictionary = new IDictionary<string, object>;
        foreach (string key in keys)
        {
            dictionary.Add(key, dataRow[key]);
        }
        return dictionary;
    }

这是我的 LINQ 查询:

var duplicates = dataTable.AsEnumerable().GroupBy(r => Key(r, keys)).Where(c => c.Count() > 1).ToList();

如果我从 Key() 方法以匿名类型硬编码,则 GroupBy 子句有效。基本上我只需要根据键列表中的值动态设置 GroupBy 子句。

【问题讨论】:

  • 我认为您混淆了 anonymous 类型 - 它们是临时定义的,但是是 strongly 类型的对象,与 dynamic i> 类型,它可以具有任意数量的运行时定义的属性,如果我理解正确的话,这就是您在这里尝试做的事情。我有一种感觉,你需要的是既不是。你能详细说明一下 GroupBy 的事情,显示将使用这个匿名对象的代码吗?
  • 正如@AvnerShahar-Kashtan 所说,您可能会混淆动态和匿名。如果您对从字典创建动态对象感到满意,这可能会有所帮助 - stackoverflow.com/questions/7595416/…
  • @AvnerShahar-Kashtan - 我在上面的 LINQ 查询中添加了。
  • Simon - 我之前从您的链接中尝试过该代码,但无法使其正常工作。更具体地说,动态对象似乎没有该 Property 属性。
  • 好的,现在更清楚了。您有一个数据表,您希望按一个复合属性对它进行分组,该复合属性由编译时未知的几列组成。对吗?

标签: c# linq group-by anonymous-types idictionary


【解决方案1】:

简化您的问题,您想要的是能够根据运行时属性对项目列表进行分组,该运行时属性可能由该项目的一个或多个属性组成。本质上,这意味着您需要一个将项目转换为键的选择器函数(这是您的Key 方法)。

为了让 GroupBy 工作,它需要能够比较键的任意两个实例以查看它们是否相等。这意味着密钥需要实现一个有意义的Equals() 方法,或者您需要一个为您完成工作的IEqualityComparer 实现。在这种情况下,我不会费心创建新的 Key,只需编写一个可以直接比较两个 DataRows 的 Equality Comparer:

var duplicates = dataTable
        .AsEnumerable()
        .GroupBy(r => r, new MyDataRowComparer(keys))
        .Where(c => c.Count() > 1)
        .ToList();


internal class MyDataRowComparer : IEqualityComparer<DataRow>
{
    private readonly string[] _keys;

    public MyDataRowComparer(string[] keys)
    {
        _keys = keys; // keep the keys to compare by.
    }

    public bool Equals(DataRow x, DataRow y)
    {
        // a simple implementation that checks if all the required fields 
        // match. This might need more work.
        bool areEqual = true;
        foreach (var key in _keys)
        {
            areEqual &= (x[key] == y[key]);
        }
        return areEqual;
    }

    public int GetHashCode(DataRow obj)
    {
        // Add implementation here to create an aggregate hashcode.
    }
}    

【讨论】:

  • 谢谢你,Avner。我添加了 GetHashCode() 实现并调整了 Equals()。我不得不使用 object.Equals() 函数来比较值,因为 == 每次都返回 false。另一种选择是将 ToString() 添加到每个值。
猜你喜欢
  • 2019-04-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-15
  • 1970-01-01
  • 1970-01-01
  • 2016-12-25
  • 1970-01-01
相关资源
最近更新 更多