简体   繁体   English

在 LInq Query .Where() 中,IDictionary 扩展实际上并未运行

[英]IDictionary extension not actually running while in LInq Query .Where()

I have an extension for an IDictionary that is meant to allow it to be case insensitive when doing a contains:我有一个 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;
}

But it never seems to run, hitting breakpoints or anything, while inside a .Where() :但在 .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;
}

However it will run if inside a for loop:但是,如果在 for 循环中,它将运行:

foreach(var keys in onlyKeys)
    {
        fromImport.ContainsKeyIgnoreCase(keys.key);
    }

Wondering if I'm doing something wrong or simply why it would refuse to actually run through the extension.想知道我是否做错了什么,或者只是为什么它会拒绝实际运行扩展。

Continuing on my comment, and as @Kirk Woll pointed out, this is an example of a "deferred execution".继续我的评论,正如@Kirk Woll 所指出的,这是“延期执行”的一个例子。 In simple words the execution of Where method is delayed until you would need that data.简而言之, Where方法的执行会延迟到您需要该数据为止。

In your case, you have following code:在您的情况下,您有以下代码:

    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;

in this moment of execuion there is nothing that accessing the data itself, you do return it, but not interacting.在执行的这一刻,没有什么可以访问数据本身,您确实返回了它,但没有进行交互。

if you create and test this example (breakpoint is at return in where):如果您创建并测试此示例(断点位于返回位置):

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());

you will see that the breakpoint will not be hit until 10 seconds mark (loot at this screenshot: https://imgur.com/a/uPaAOvS )您将看到断点直到 10 秒标记才会被命中(在此屏幕截图中掠夺: https ://imgur.com/a/uPaAOvS)

As to you comment about breakpoint is never hit, make sure you return a reference to a enumerable rather than a copy, and if you actually interact with it.至于您对断点的评论永远不会被击中,请确保您返回对可枚举而不是副本的引用,并且如果您实际与之交互。

As a crude solution, you could make this change to your code:作为一个粗略的解决方案,您可以对代码进行以下更改:


    var newItems = fromImport
        .Where(i => !items.ContainsKeyIgnoreCase(i.Key))
        .Select(i => i.Value)
        .ToList();

this will force the execution of your query, because data needs to be copied into new list这将强制执行您的查询,因为需要将数据复制到新列表中

There is nothing processing the query:没有处理查询:

fromImport
    .Where(i => items.ContainsKeyIgnoreCase(i.Key))
    .ForEach(i => { i.Value.ID = items.AtKey(i.Key).ID; });

What is the definition of the ForEach() extenaion method? ForEach() 扩展方法的定义是什么? It might be that the ForEach() is returning an iterator (IEnumerable<>);可能是 ForEach() 正在返回一个迭代器 (IEnumerable<>); you need to do something with it to process the query.你需要用它来处理查询。 For example:例如:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM