0

我有一个开发场景,我正在使用 Linq 加入两个集合;包含表示元数据的列标题对象的单个列表,以及由 Web 服务调用产生的 kv 字典的枚举。我目前可以for通过字典枚举迭代 (),并将单个标题列表加入当前的 kv 字典而不会出现问题。加入后,我为每次迭代发出一个精选的字典值数组。

我想做的是消除for循环,并将单个标题列表直接加入整个枚举。我非常了解 1 对 1 集合连接,但 1 对 N 语法让我难以理解。

细节

我有以下工作方法:

public void GetQueryResults(DataTable outputTable)
{
    var odClient = new ODataClient(UrlBase);
    var odResponse = odClient.FindEntries(CommandText);

    foreach (var row in odResponse)
    {
        var rowValues = OutputFields
            .Join(row, h => h.Key, r => r.Key, 
                (h, r) => new { Header = h, ResultRow = r })
            .Select(r => r.ResultRow.Value);

        outputTable.Rows.Add(rowValues.ToArray());
    }
}

odResponse包含IEnumerable<IDictionary<string, object>>OutputFields包含IList<QueryField>.Join生成包含匹配字段元数据 ( .Header) 和响应 kv 对 ( )的匿名枚举.ResultRow;最后,.Select为行消费发出匹配的响应值。该OutputField集合如下所示:

class QueryField
{
    public string Key { get; set; }
    public string Label { get; set; }
    public int Order { get; set; }
}

声明为:

public IList<QueryField> OutputFields { get; private set; }

通过将字段标题集合连接到响应行,我可以从响应中只提取我需要的列。如果标题键包含 { "size", "shape", "color" } 并且响应键包含 { "size", "mass", "color", "longitude", "latitude" },我将得到一个数组{ "size", "shape", "color" } 的值,其中shape为空,而masslongitudelatitude值被忽略。对于这种情况,我不关心排序。这一切都是一种享受。

问题

我想做的是重构此方法以返回值数组行的枚举,并让调用者管理数据的使用:

public IEnumerable<string[]> GetQueryResults()
{
    var odClient = new ODataClient(UrlBase);
    var odResponse = odClient.FindEntries(CommandText);

    var responseRows = //join OutputFields to each row in odResponse by .Key

    return responseRows;
}

后续问题

用于此重构的 Linq 实现的解决方案是否需要立即扫描枚举,或者它是否可以传回惰性结果?重构的目的是在引起冗余集合扫描的情况下改进封装。我总是可以构建命令式循环以艰难的方式重新格式化响应数据,但我希望 Linq 提供的是类似于闭包的东西。

非常感谢您花时间阅读本文;任何建议表示赞赏!

4

1 回答 1

0

我不完全确定你的意思,但可能是你的意思是这样的吗?

public IEnumerable<object[]> GetQueryResults()
{

    var odClient = new ODataClient(UrlBase);
    var odResponse = odClient.FindEntries(CommandText);


    // i'd rather you linq here.
    var responseRows = from row in odResponse
                       select new object[] 
                       { 
                           from field in row
                           join outputfield in OutputFields 
                               on field.Key equals outputfield.Key
                           select field.Value 
                       };

    return responseRows;

}

而不是填充数据表。这将创建一个对象数组并用 field.Value 填充它,其中 field.Key 存在于输出字段中。整个事情被封装在一个IEnumerable. (来自 odResponse 中的行)

用法:

var responseRows = GetQueryResults2();

foreach(var rowValues in responseRows)
    outputTable.Rows.Add(rowValues);

这里的技巧是,在一个查询中,您迭代一个列表并在字段上创建一个子查询,并将子查询结果直接存储在object[]. object[]仅在迭代时创建responseRows。这是我认为的第二个问题的答案-> Lazy result

于 2013-09-27T23:26:10.873 回答