IDictionary 扩展实际上不是 运行 而在 LInq 查询中.Where()
IDictionary extension not actually running while in LInq Query .Where()
我有一个 IDictionary 的扩展,目的是让它在执行包含时不区分大小写:
public static bool ContainsKeyIgnoreCase<TKey, TModel>(this IDictionary<TKey, TModel> dictionary, TKey key)
{
bool? keyExists;
var keyString = key as string;
if (keyString != null)
{
keyExists =
dictionary.Keys.OfType<string>()
.Any(k => string.Equals(k, keyString, StringComparison.OrdinalIgnoreCase));
}
else
{
keyExists = dictionary.ContainsKey(key);
}
return keyExists ?? false;
}
但它似乎从来没有 运行,在 .Where() :
中遇到断点或任何东西
public IEnumerable<TModel> PopulateIdsFromExistingRowsAndReturnNewRowsToCreate<TFromDBDto, TKey, TModel>(
IEnumerable<TFromDBDto> fromDatabase,
IDictionary<TKey, TModel> fromImport,
Func<TFromDBDto, TKey> keySelector)
where TFromDBDto : class, IGuidDataTransferObject
where TModel : class, IModel<Guid>
{
var groupedItems = fromDatabase
.GroupBy(i => keySelector(i));
var onlyKeys = groupedItems.Select(i => new { key = i.Key, value = i.First() });
var filtered = onlyKeys.Where(i => fromImport.ContainsKeyIgnoreCase(i.key));
var items = filtered.ToDictionary(i => i.key, i => i.value);
var newItems = fromImport
.Where(i => !items.ContainsKeyIgnoreCase(i.Key))
.Select(i => i.Value);
fromImport
.Where(i => items.ContainsKeyIgnoreCase(i.Key))
.ForEach(i => { i.Value.ID = items.AtKey(i.Key).ID; });
return newItems;
}
然而,如果在 for 循环中,它将 运行:
foreach(var keys in onlyKeys)
{
fromImport.ContainsKeyIgnoreCase(keys.key);
}
想知道我是不是做错了什么,或者只是为什么它会拒绝 运行 通过扩展。
没有任何处理查询:
fromImport
.Where(i => items.ContainsKeyIgnoreCase(i.Key))
.ForEach(i => { i.Value.ID = items.AtKey(i.Key).ID; });
ForEach() 扩展方法的定义是什么?
可能是 ForEach() 正在返回一个迭代器 (IEnumerable<>);你需要用它做一些事情来处理查询。例如:
var myStuff = fromImport
.Where(i => items.ContainsKeyIgnoreCase(i.Key))
.ForEach(i => { i.Value.ID = items.AtKey(i.Key).ID; })
.ToList(); // <-- this will run the query
继续我的评论,正如@Kirk Woll 所指出的,这是一个
“延期执行”。简而言之,Where
方法的执行会延迟到您需要该数据时。
在你的例子中,你有以下代码:
var newItems = fromImport
.Where(i => !items.ContainsKeyIgnoreCase(i.Key))
.Select(i => i.Value);
fromImport
.Where(i => items.ContainsKeyIgnoreCase(i.Key))
.ForEach(i => { i.Value.ID = items.AtKey(i.Key).ID; });
return newItems;
在执行的这一刻,没有什么可以访问数据本身,你可以 return 它,但不能交互。
如果您创建并测试此示例(断点位于 return 中的位置):
Dictionary<string, int> dict = new Dictionary<string, int>();
dict.Add("a", 0);
dict.Add("b", 0);
dict.Add("c", 0);
dict.Add("A", 0);
dict.Add("B", 0);
dict.Add("C", 0);
var newItems = dict
.Where(i => {
return !dict.ContainsKeyIgnoreCase(i.Key);
})
.Select(i => i.Value);
Thread.Sleep(10000);
Console.WriteLine(newItems.Count());
你会看到在 10 秒标记之前不会命中断点
(在此屏幕截图中抢劫:https://imgur.com/a/uPaAOvS)
至于你关于从未命中断点的评论,请确保你 return 对可枚举对象而不是副本的引用,并且如果你确实与它交互。
作为粗略的解决方案,您可以对代码进行以下更改:
var newItems = fromImport
.Where(i => !items.ContainsKeyIgnoreCase(i.Key))
.Select(i => i.Value)
.ToList();
这将强制执行您的查询,因为需要将数据复制到新列表中
我有一个 IDictionary 的扩展,目的是让它在执行包含时不区分大小写:
public static bool ContainsKeyIgnoreCase<TKey, TModel>(this IDictionary<TKey, TModel> dictionary, TKey key)
{
bool? keyExists;
var keyString = key as string;
if (keyString != null)
{
keyExists =
dictionary.Keys.OfType<string>()
.Any(k => string.Equals(k, keyString, StringComparison.OrdinalIgnoreCase));
}
else
{
keyExists = dictionary.ContainsKey(key);
}
return keyExists ?? false;
}
但它似乎从来没有 运行,在 .Where() :
中遇到断点或任何东西public IEnumerable<TModel> PopulateIdsFromExistingRowsAndReturnNewRowsToCreate<TFromDBDto, TKey, TModel>(
IEnumerable<TFromDBDto> fromDatabase,
IDictionary<TKey, TModel> fromImport,
Func<TFromDBDto, TKey> keySelector)
where TFromDBDto : class, IGuidDataTransferObject
where TModel : class, IModel<Guid>
{
var groupedItems = fromDatabase
.GroupBy(i => keySelector(i));
var onlyKeys = groupedItems.Select(i => new { key = i.Key, value = i.First() });
var filtered = onlyKeys.Where(i => fromImport.ContainsKeyIgnoreCase(i.key));
var items = filtered.ToDictionary(i => i.key, i => i.value);
var newItems = fromImport
.Where(i => !items.ContainsKeyIgnoreCase(i.Key))
.Select(i => i.Value);
fromImport
.Where(i => items.ContainsKeyIgnoreCase(i.Key))
.ForEach(i => { i.Value.ID = items.AtKey(i.Key).ID; });
return newItems;
}
然而,如果在 for 循环中,它将 运行:
foreach(var keys in onlyKeys)
{
fromImport.ContainsKeyIgnoreCase(keys.key);
}
想知道我是不是做错了什么,或者只是为什么它会拒绝 运行 通过扩展。
没有任何处理查询:
fromImport
.Where(i => items.ContainsKeyIgnoreCase(i.Key))
.ForEach(i => { i.Value.ID = items.AtKey(i.Key).ID; });
ForEach() 扩展方法的定义是什么? 可能是 ForEach() 正在返回一个迭代器 (IEnumerable<>);你需要用它做一些事情来处理查询。例如:
var myStuff = fromImport
.Where(i => items.ContainsKeyIgnoreCase(i.Key))
.ForEach(i => { i.Value.ID = items.AtKey(i.Key).ID; })
.ToList(); // <-- this will run the query
继续我的评论,正如@Kirk Woll 所指出的,这是一个
“延期执行”。简而言之,Where
方法的执行会延迟到您需要该数据时。
在你的例子中,你有以下代码:
var newItems = fromImport
.Where(i => !items.ContainsKeyIgnoreCase(i.Key))
.Select(i => i.Value);
fromImport
.Where(i => items.ContainsKeyIgnoreCase(i.Key))
.ForEach(i => { i.Value.ID = items.AtKey(i.Key).ID; });
return newItems;
在执行的这一刻,没有什么可以访问数据本身,你可以 return 它,但不能交互。
如果您创建并测试此示例(断点位于 return 中的位置):
Dictionary<string, int> dict = new Dictionary<string, int>();
dict.Add("a", 0);
dict.Add("b", 0);
dict.Add("c", 0);
dict.Add("A", 0);
dict.Add("B", 0);
dict.Add("C", 0);
var newItems = dict
.Where(i => {
return !dict.ContainsKeyIgnoreCase(i.Key);
})
.Select(i => i.Value);
Thread.Sleep(10000);
Console.WriteLine(newItems.Count());
你会看到在 10 秒标记之前不会命中断点 (在此屏幕截图中抢劫:https://imgur.com/a/uPaAOvS)
至于你关于从未命中断点的评论,请确保你 return 对可枚举对象而不是副本的引用,并且如果你确实与它交互。
作为粗略的解决方案,您可以对代码进行以下更改:
var newItems = fromImport
.Where(i => !items.ContainsKeyIgnoreCase(i.Key))
.Select(i => i.Value)
.ToList();
这将强制执行您的查询,因为需要将数据复制到新列表中