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

时间:2012-04-27 03:25:10

标签: c# delegates

我的开发人员朋友告诉我,使用委托的循环速度要快得多,而且我想对它进行基准测试,但是我无法将它们的工作原理连接起来。

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

    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;
    }

这对于中小型帐户列表相当表现,但使用委托会更快吗?坦率地说,委托逻辑似乎与我的思维过程正确地运作,因为我正在摸不着写这个。

有人能提供一种使用委托重写的方法吗?

3 个答案:

答案 0 :(得分:5)

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

等效语法为:

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

它既慢又难以阅读。委托调用比普通方法调用慢。您上面的语法更快,更容易阅读。

答案 1 :(得分:2)

  

有人能提供一种使用委托重写的方法吗?

但是你已经使用代表了!这就是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());

现在它更具可读性。

答案 2 :(得分:0)

如果要使用foreach构建新词典,Dictionary.Add构造是正确的构造。你总是可以从现有字典中选择创建一个新字典,但速度会慢一些。

但是,关于可读性,这不是更容易吗?

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;
}