[英]How would I use a delegate in this scenario?
A developer friend of mine tells me that loops are much faster using delegates, and I'd like to benchmark it, but I'm having trouble connecting the dots on how it works. 我的一个开发人员朋友告诉我,使用委托的循环要快得多,而且我想对它进行基准测试,但是我无法将它们的工作原理连接起来。
Consider the following balance calculator. 考虑以下平衡计算器。 This basically takes a list of accounts and adds the initial value (starting balance) if it exists to the total credits value if it exist and subtracts the total debits value for each account: 这基本上是一个帐户列表,如果它存在,则将初始值(起始余额)添加到总信用值(如果存在)并减去每个帐户的总借方值:
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;
}
This is fairly performant on small to medium account lists, but would using delegates be faster? 这在中小型帐户列表中是相当高效的,但使用委托会更快吗? And frankly, delegate logic seems to be operating at right angles to my thought processes, because I'm scratching my head how to even write this. 坦率地说,委托逻辑似乎与我的思维过程正确地运作,因为我正在摸不着如何写这个。
Can anyone offer a way to rewrite this using delegates? 任何人都可以提供一种使用委托重写这个的方法吗?
I'm assuming your friend is referring to something like the ForEach
method on the List<T>
class. 我假设你的朋友指的是List<T>
类上的ForEach
方法。 The short answer to your question is no . 对你的问题的简短回答是否定的 。
The equivalent syntax would be: 等效的语法是:
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)
));
This is in no way better than the way you have it above. 这绝不比你上面的方式更好。 It is both slower and more difficult to read. 它既慢又难以阅读。 Delegate invocation is slower than ordinary method invocation. 委托调用比普通方法调用慢。 The syntax you have above is both faster and easier to read. 您上面的语法更快,更容易阅读。
Can anyone offer a way to rewrite this using delegates? 任何人都可以提供一种使用委托重写这个的方法吗?
But you are using delegates already! 但是你已经在使用代表了! That's what the lambdas are being converted to. 这就是lambda被转换成的东西。 The question about whether to use a delegate or not for the loop-body for performance reasons is a little strange when so many delegate invocations are being used just to produce each item of the sequence. 出于性能原因,是否使用委托是否为循环体的问题有点奇怪,因为如此多的委托调用仅用于生成序列的每个项目。
Anyway, Adam Robinson has already covered how you would List.ForEach
to execute a side-effect on each item of a list and the associated readability and performance implications, so I won't go into that. 无论如何,Adam Robinson已经介绍了List.ForEach
如何对列表中的每个项目执行副作用以及相关的可读性和性能影响,所以我不会涉及到这一点。
But here's how I would write your method if the marginal overhead of LINQ and delegate invocations were not a deciding factor: 但是,如果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());
Now that's much more readable. 现在这更具可读性了。
The foreach
construct is the right one if you want to build a new dictionary using Dictionary.Add
. 如果要使用Dictionary.Add
构建新字典,则foreach
构造是正确的构造。 You can always just select from the existing dictionary to create a new one, but that will be slower. 您始终可以从现有字典中选择以创建新字典,但这样会更慢。
However, as to readability, isn't this much easier? 但是,至于可读性,这不是更容易吗?
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;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.