访问对象的字段与制作副本的性能/代码可读性

时间:2016-02-13 12:03:04

标签: c# performance coding-style

我很难准确解释标题中的含义,因此我会立即提供代码示例。

看看下面的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);
    }
}

考虑到两个因素 - 性能和可读性,我想知道哪种风格更受欢迎/推荐。

  1. [性能]在第二个示例中,编译器足够智能,注意到giveaway对象只能由一个线程访问,因此访问giveaway.CreatorID不必在每次调用时解析,而是仅在第一个?有没有建议使用第一或第二种方法表现?我知道正在做类似的事情,例如在for循环中,当我们使用例如string的Length属性(当编译为CIL时,字符串的长度只计算一次)。如果编译器不够聪明,那么将它存储在变量中也是明智的。
  2. [可读性]您更喜欢使用哪种方式?选择取决于我们访问给定字段的次数吗?如果它被访问2次或更多次,我倾向于复制该字段。这是错的吗?那么长的"链#",例如giveaway.CreatorID.Achievements.Count
  3. 在决定是使用第一种还是第二种方法之前,还有其他因素我应该考虑吗?也许我所问的并不重要,因为答案应该是显而易见的?
  4. 我很抱歉,如果我提出的问题完全是胡说八道并且根本不重要,但我不时会听到其他程序员的意见他们对给定的感受如何主题,所以我将来可以改进我的代码风格。现在我倾向于复制该字段,如果它被访问超过1次,但我不知道是否需要(从性能方面),或推荐(从代码可读性)一个)。

    提前谢谢。

1 个答案:

答案 0 :(得分:1)

使用临时变量作为微优化没有意义,但是随着可读性的提高,它确实有意义。

除非Giveawaystruct,否则编译器不可能知道该对象只被一个线程访问。但是,它不需要知道,因为它假设发生了什么:除非CreatorID标记为volatile,否则编译器保留仅访问它一次的权利,并且在后续调用中使用缓存副本。这是一个很长的说法"编译器足够聪明,可以为你制作副本"

制作命名副本的一个重要的可读性结果是它可以防止阅读器水平滚动。这是一个大问题,因为水平滚动会降低读者的速度。如果你可以给变量一个简短的名字而不会发疯,那就去吧。 (creatorID没问题; cid可能不够具有描述性。)