在这种情况下,我将如何使用委托

本文关键字:何使用 这种情况下 | 更新日期: 2023-09-27 18:32:27

我的一位开发人员朋友告诉我,使用委托的循环要快得多,我想对其进行基准测试,但是我无法连接它的工作原理。

考虑以下余额计算器。 这基本上需要一个帐户列表,并将初始值(起始余额)(如果存在)添加到总贷方值(如果存在)并减去每个帐户的总借方值:

    private static IDictionary<string, decimal> CalculateBalances(
        IDictionary<string, decimal> initialValue, 
        IDictionary<string, decimal> credits, 
        IDictionary<string, decimal> debits)
    {
        var r = new Dictionary<string, decimal>();
        foreach (var key in initialValue.Select(k => k.Key)
            .Concat(credits.Select(k => k.Key))
            .Concat(debits.Select(k => k.Key))
            .Distinct())
        {
            r.Add(key,
                (initialValue.ContainsKey(key) ? initialValue[key] : 0M)
                + (credits.ContainsKey(key) ? credits[key] : 0M)
                - (debits.ContainsKey(key) ? debits[key] : 0M)
                );
        }
        return r;
    }

这在中小型帐户列表中相当有效,但使用委托会更快吗? 坦率地说,委托逻辑似乎与我的思维过程成直角,因为我正在挠头如何写这个。

任何人都可以提供一种使用委托重写它的方法吗?

在这种情况下,我将如何使用委托

我假设你的朋友指的是List<T>类上的ForEach方法。对您的问题的简短回答是否定的

等效语法为:

initialValue.Select(k => k.Key)
            .Concat(credits.Select(k => k.Key))
            .Concat(debits.Select(k => k.Key))
            .Distinct()
            .ToList()
            .ForEach(var => r.Add(key,
                (initialValue.ContainsKey(key) ? initialValue[key] : 0M)
                + (credits.ContainsKey(key) ? credits[key] : 0M)
                - (debits.ContainsKey(key) ? debits[key] : 0M)
                ));

绝不比你上面的方式更好。它既慢又难读。委托调用比普通方法调用慢。您上面的语法既更快又更容易阅读。

任何人都可以提供一种使用委托重写它的方法吗?

但是您已经在使用委托了!这就是 lambda 正在转换为的内容。当如此多的委托调用仅用于生成序列的每个项目时,关于是否出于性能原因对循环体使用委托的问题有点奇怪。

无论如何,Adam Robinson已经介绍了如何List.ForEach对列表中的每个项目执行副作用以及相关的可读性和性能影响,所以我不会深入讨论。

但是,如果 LINQ 和委托调用的边际开销不是决定性因素,我将如何编写您的方法:

return initialValue
       .Concat(credits)
       .Concat(debits.Select(kvp => new KeyValuePair<string, decimal>(kvp.Key, -kvp.Value)))
       .GroupBy(kvp => kvp.Key, kvp => kvp.Value)
       .ToDictionary(group => group.Key, group => group.Sum());

现在,这更具可读性。

如果要使用 Dictionary.Add 构建新字典,则foreach结构是正确的。您始终可以从现有词典中进行选择以创建新词典,但这会更慢。

但是,就可读性而言,这不是容易得多吗?

private static decimal GetOrZero(this IDictionary<string,decimal> dict, string key)
{
    decimal value = 0;
    dict.TryGetValue(key, out value);
    return value;
}
private static IDictionary<string, decimal> CalculateBalances(
    IDictionary<string, decimal> initialValue, 
    IDictionary<string, decimal> credits, 
    IDictionary<string, decimal> debits)
{   
    var r = new Dictionary<string, decimal>();
    var accounts = initialValue.Keys.Union(debits.Keys).Union(credits.Keys);
    foreach (var accounts in accounts)
    {
        r.Add(initialValue.GetOrZero(key) + credits.GetOrZero(key) - debits.GetOrZero(key));
    }
    return r;
}