我喜歡在 C# 中使用的一種常見模式是,我不是先檢查集合中是否存在某物,然后Any再用:FirstFirstOrDefault
List<Person> people = ...;
Person found;
if ((found = people.FirstOrDefault(x => x.Age > 10)) != null) {
// Found person with age over 10, and we have them in 'found'
//...
}
當找到的東西是參考型別時,這有效,并且可以為空。但是,我試圖對 aDictionary的條目做同樣的事情:
Dictionary<(int X, int Y), ITileData<(int X, int Y)>> srchField = new();
KeyValuePair<(int X, int Y), ITileData<(int X, int Y)>> next;
while ((next = srchField.FirstOrDefault(x => !x.Value.Reached)) != null) {
// Found next, and we have it in 'next'
//...
}
但是,這不起作用,因為srchField.FirstOrDefault(...)回傳 a KeyValuePair<TKey, TValue>,它是一個結構。Any我可以通過首先呼叫on來解決這個問題srchField,然后First如果找到任何東西,則使用相同的謂詞呼叫Any,但這必須進行兩次相同的搜索。有什么辦法可以在此處進行二合一檢查并存盤,只在 LINQ 中執行一次字典搜索?
uj5u.com熱心網友回復:
感謝@TheodorZoulias 為我指明了正確的方向,并受到@Samuel 的答案和@JonSkeet 的優秀代碼解決方案的結合的啟發(我實際上并沒有意識到,如果 LINQ.Take(1)只找到 0 個元素,它實際上會給你一個可列舉 0 而不是拋出例外),我想出了一個可以很好地執行此操作的擴展方法:
public static class IEnumerableExtensions {
public static bool TryGetFirst<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate, out TSource first) {
if (predicate == null) {
throw new ArgumentNullException(nameof(predicate));
}
var query = source.Where(predicate).Take(1).ToList();
if (query.Count == 0) {
first = default;
return false;
}
first = query[0];
return true;
}
}
示例用法:
while (srchField.TryGetFirst(x => !x.Value.Reached, out KeyValuePair<(int X, int Y), ITileData<(int X, int Y)>> next)) {
var key = next.Key;
var val = next.Value;
// ... use eg. key.X, key.Y, and val ...
}
uj5u.com熱心網友回復:
如果您想忽略搜索中的鍵并且您的值是參考型別,則可以只使用Values字典的屬性:
srchField.Values.FirstOrDefault(!v => v.Reached)
如果你想用鍵做一些事情,它會有點笨拙:
srchField.Where(kvp => Predicate(kvp.Key)).Select(kvp => kvp.Value).FirstOrDefault()
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/522807.html
標籤:C#表现林克值类型
