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

本文关键字:性能 代码 可读性 副本 对象 字段 访问 | 更新日期: 2023-09-27 18:34:24

我很难准确地解释我在标题中的意思,所以我会立即提供代码示例。

请查看以下 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循环中,当我们使用 例如 字符串的Length属性(编译为 CIL 时,字符串的长度仅计数一次(。如果编译器不够聪明,无法做到这一点,那么将其存储在变量中也是明智的。
  2. [可读性] 您更喜欢使用哪种方式?选择是否取决于我们访问给定字段的次数?如果该字段被访问 2 次或更多次,我倾向于复制该字段。有错吗?很长的"链条"呢,比如giveaway.CreatorID.Achievements.Count
  3. 在决定使用第一种方法还是第二种方法之前,我应该考虑其他因素吗?也许我问的甚至无关紧要,因为答案应该是显而易见的?

如果我问的完全是胡说八道,这根本不重要,我很抱歉,但有时我喜欢听到其他程序员对给定主题的看法,这样我就可以改进我的代码风格将来。目前,如果访问该字段超过 1 次,我倾向于复制该字段,但我不知道它是必需的(从性能方面(还是推荐的(来自代码可读性(。

提前谢谢你。

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

使用临时变量作为微优化没有意义,但作为可读性改进确实有意义。

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

制作命名副本的一个重要可读性结果是,它可以避免读者水平滚动。这是一件大事,因为水平滚动会减慢读者的速度。如果你能给一个变量一个短名称而不会发疯,那就去做吧。( creatorID很好; cid可能没有足够的描述性(。