LINQ查询 - 根据具有与字符串匹配的属性的值选择键?

时间:2011-06-16 14:43:16

标签: c# linq dictionary foreach key-value

我有一个IDictionary

我需要选择Bar.Prop1与字符串值匹配的第一个Foo。

public class Foo { }

public class Bar
{
    public String Prop1 { get; set; }
}

现在我就这样......

foreach (var kvp in MyDictionary)
{
    if (kvp.Value.Prop1 == theString)
    {
        var key = kvp.Key;
        //Do something with it
        break;
    }
}

但这似乎并不像LINQ Query一样干净。 ReSharper把它变成了:

foreach (var kvp in MyDictionary.Where(kvp => kvp.Value.Prop1 == theString))
{
    var key = kvp.Key;
    //Do something with it
    //break; is unnecessary because I only get one kvp back anyways.
}

我只想要匹配的第一个项目,因为我不希望得到多个KVP。这违背了业务逻辑,因此单元测试会处理这个问题。

3 个答案:

答案 0 :(得分:7)

  

我只想要第一个项目   比赛,因为我没想到   获得多个KVP。那   违背了业务逻辑,所以   单元测试负责这一点。

如果是这种情况,我认为你需要对你的意图使用更强的代码保证,那就是Single(或SingleOrDefault)方法。 First将返回与给定谓词匹配的任意多个的第一个对象。如果很多违背了您的期望和业务规则,那么这似乎是一个错误。这样对待它。

var key = MyDictionary.Single(pair => pair.Value.Prop1 == someValue).Key;

使用Single,如果序列中有多个匹配项,则会导致异常。

SingleOrDefault允许0或1,但永远不会更多。如果使用这种方法,您需要捕获结果并在执行其他操作(触发方法,访问属性等)之前与null进行比较。

答案 1 :(得分:5)

var key = MyDictionary.First(kvp => kvp.Value.Prop1 == theString).Key;

答案 2 :(得分:4)

@Bala R的回答是正确的,但Anthony Pegram在他对OP的评论中提出了非常好的观点。如果您使用不同的键执行此操作多次,则应该执行的操作是反转字典,因此每次需要值时都不必遍历整个集合。

// Do this just once: it's expensive
var reverseDict = MyDictionary.ToDictionary(kvp => kvp.Value.Prop1, kvp => kvp.Key);

...
// Do this as many times as you need: it's cheap
var key = reverseDict[someValue];