重构linq声明

时间:2011-02-22 03:03:18

标签: c# linq refactoring

我有一个linq表达式,我一直在LINQPad中玩,我想重构表达式,用一次测试替换idx == -1的所有测试。此输入数据是用于缓存Active Directory信息的数据库上的自由文本搜索的结果。搜索返回匹配数据库行中的显示名称和关联的摘要数据的列表。我想从该列表中提取显示名称和匹配的Active Directory条目。有时匹配仅出现在显示名称上,因此可能没有进一步的上下文。在下面的示例中,字符串“Sausage”旨在作为返回 matches 数组中两个项目的搜索词。显然,实际搜索不会出现这种情况,因为第二个数组项中的 Sausage 不匹配。

var matches = new [] 
{
    new { displayName = "Sausage Roll", summary = "|Title: Network Coordinator|Location: Best Avoided|Department: Coordination|Email: Sausage.Roll@somewhere.com|" },
    new { displayName = "Hamburger Pattie",  summary = "|Title: Network Development Engineer|Location: |Department: Planning|Email: Hamburger.Pattie@somewhere.com|" },
};

var context = (from match in matches
                let summary = match.summary
                let idx = summary.IndexOf("Sausage")
                let start = idx == -1 ? 0 : summary.LastIndexOf('|', idx) + 1
                let stop = idx == -1 ? 0 : summary.IndexOf('|', idx)
                let ctx = idx == -1 ? "" : string.Format("...{0}...", summary.Substring(start, stop - start))
                select new { displayName = match.displayName, summary = ctx, })
                .Dump();

我正在尝试为搜索结果创建一个名称列表和一些上下文(如果存在)。下面的输出表示 Dump()显示的内容,并且是正确的结果:

displayName        summary 
----------------   ------------------------------------------
Sausage Roll       ...Email: Sausage.Roll@somewhere.com...
Hamburger Pattie

编辑:正则表达式版本在下面,绝对更整洁:

Regex reg = new Regex(@"\|((?:[^|]*)Sausage[^|]*)\|");      
var context = (from match in matches
                let m = reg.Match(match.summary)
                let ctx = m.Success ? string.Format("...{0}...", m.Groups[1].Value) : ""
                select new { displayName = match.displayName, context = ctx, })
                .Dump();

3 个答案:

答案 0 :(得分:2)

(我知道这不能回答你的具体问题),但无论如何,这是我的贡献:

你还没有真正描述你的数据是如何进入的。正如@Joe建议的那样,你可以使用正则表达式或拆分字段,就像我在下面所做的那样。

无论哪种方式,我都建议重构代码以允许进行单元测试。

否则,如果您的数据无效/损坏,您将在linq查询中收到运行时错误。

    [TestMethod]
    public void TestMethod1()
    {
        var matches = new[] 
        {
            new { displayName = "Sausage Roll", summary = "|Title: Network Coordinator|Location: Best Avoided|Department: Coordination|Email: Sausage.Roll@somewhere.com|" },
            new { displayName = "Hamburger Pattie",  summary = "|Title: Network Development Engineer|Location: |Department: Planning|Email: Hamburger.Pattie@somewhere.com|" },
        };

        IList<Person> persons = new List<Person>();
        foreach (var m in matches)
        {
            string[] fields = m.summary.Split('|');
            persons.Add(new Person { displayName = m.displayName, Title = fields[1], Location = fields[2], Department = fields[3] });
        }

        Assert.AreEqual(2, persons.Count());
    }

    public class Person
    {
        public string displayName { get; set; }
        public string Title { get; set; }
        public string Location { get; set; }
        public string Department { get; set; }
        /* etc. */
    }

答案 1 :(得分:1)

或类似的东西:

    Regex reg = new Regex(@"^|Email.*|$");
    foreach (var match in matches)
    {
        System.Console.WriteLine(match.displayName + " ..." + reg.Match(match.summary) + "... ");
    }

我没有对此进行测试,可能甚至没有正确的语法,只是为了让您了解如何使用正则表达式进行操作。

<强>更新 好的,我已经看到了你的答案,你发布它很好,因为我觉得我没有清楚地解释它。 我希望你的答案在最后看起来像这样(现在用LINQPad测试,现在我明白你使用LINQPad是什么意思,因为它实际上运行的是一个C#程序而不仅仅是linq命令,真棒!)无论如何这应该是它应该的看起来像:

foreach (var match in matches)
    Console.WriteLine(string.Format("{0,-20}...{1}...", match.displayName, Regex.Match(match.summary, @"Email:(.*)[|]").Groups[1]));
}

就是这样,整个事情,完全取出linq! 我希望这可以解决它,你根本不需要linq。

答案 2 :(得分:0)

像这样?

var context = (from match in matches
                let summary = match.summary
                let idx = summary.IndexOf("Sausage")
                let test=idx == -1 
                let start =test ? 0 : summary.LastIndexOf('|', idx) + 1
                let stop = test ? 0 : summary.IndexOf('|', idx)
                let ctx = test ? "" : string.Format("...{0}...", summary.Substring(start, stop - start))
                select new { displayName = match.displayName, summary = ctx, })
                .Dump();