我很难准确解释标题中的含义,因此我会立即提供代码示例。
看看下面的C#代码:
internal static async Task OnGroupGiveawayCreated(Giveaway giveaway) {
if (giveaway == null) {
return;
}
ulong creatorID = giveaway.CreatorID;
if (creatorID == 0 || !await MySQL.UserExists(creatorID).ConfigureAwait(false)) {
return;
}
// Date
DateTime today = DateTime.Now;
if (today.Month == 9 && today.Day == 9) {
await MySQL.InsertAchievement(40, creatorID).ConfigureAwait(false);
await OnAchievementGot(creatorID).ConfigureAwait(false);
}
}
在上面的例子中,我决定将giveaway.CreatorID
的副本作为局部变量,以便在每次访问时都不需要解析对象的字段。在最坏的情况下,它总共访问了4次。
上述内容也可以在没有这样做的情况下编写:
internal static async Task OnGroupGiveawayCreated(Giveaway giveaway) {
if (giveaway == null) {
return;
}
if (giveaway.CreatorID == 0 || !await MySQL.UserExists(giveaway.CreatorID).ConfigureAwait(false)) {
return;
}
// Date
DateTime today = DateTime.Now;
if (today.Month == 9 && today.Day == 9) {
await MySQL.InsertAchievement(40, giveaway.CreatorID).ConfigureAwait(false);
await OnAchievementGot(giveaway.CreatorID).ConfigureAwait(false);
}
}
考虑到两个因素 - 性能和可读性,我想知道哪种风格更受欢迎/推荐。
giveaway
对象只能由一个线程访问,因此访问giveaway.CreatorID
不必在每次调用时解析,而是仅在第一个?有没有建议使用第一或第二种方法表现?我知道正在做类似的事情,例如在for
循环中,当我们使用例如string的Length
属性(当编译为CIL时,字符串的长度只计算一次)。如果编译器不够聪明,那么将它存储在变量中也是明智的。giveaway.CreatorID.Achievements.Count
?我很抱歉,如果我提出的问题完全是胡说八道并且根本不重要,但我不时会听到其他程序员的意见他们对给定的感受如何主题,所以我将来可以改进我的代码风格。现在我倾向于复制该字段,如果它被访问超过1次,但我不知道是否需要(从性能方面),或推荐(从代码可读性)一个)。
提前谢谢。
答案 0 :(得分:1)
使用临时变量作为微优化没有意义,但是随着可读性的提高,它确实有意义。
除非Giveaway
是struct
,否则编译器不可能知道该对象只被一个线程访问。但是,它不需要知道,因为它假设发生了什么:除非CreatorID
标记为volatile
,否则编译器保留仅访问它一次的权利,并且在后续调用中使用缓存副本。这是一个很长的说法"编译器足够聪明,可以为你制作副本"
制作命名副本的一个重要的可读性结果是它可以防止阅读器水平滚动。这是一个大问题,因为水平滚动会降低读者的速度。如果你可以给变量一个简短的名字而不会发疯,那就去吧。 (creatorID
没问题; cid
可能不够具有描述性。)