【问题标题】:C# Code readability issueC#代码可读性问题
【发布时间】:2011-05-29 00:45:19
【问题描述】:
        int scalar = creature is SpecialCreature ? (creature.IsAwesome ? 700 : 500) : (creature is NotSoNormalCreature ? 
            (creature.IsAwesome ? (creature is IGreatCreature ? 450 : 280) : 240) : 
            (creature.IsAwesome ? (creature is IGreatCreature ? 300 : 200) : 160));

我应该如何编写该代码以使其更具可读性?

我想只构建 ifs,但后来我想制作某种“ConditionFactory”怎么样?这有什么意义吗,还是对于这么简单的任务来说太复杂了?

int scalar;

if (creature is SpecialCreature)
{
    scalar = creature.IsAwesome ? 700 : 500;
}
else if (creature is NotSoNormalCreature)
{
    if (creature.IsAwesome)
    {
        scalar = creature is IGreatCreature ? 450 : 280;
    }
    else
    {
        scalar = 240;
    }
}
else
{
    if (creature.IsAwesome)
    {
        scalar = creature is IGreatCreature ? 300 : 200;
    }
    else
    {
        scalar = 160;
    }
}

【问题讨论】:

  • 给我看等价的 if-then 语法 - 这让我的眼睛受伤......
  • 这些标量值会在应用执行期间发生变化,还是对于每种生物类型都是永久性的?
  • 当生物是 SpecialCreature 并且是 IGreatCreature 或不是 IGreatCreature 时,计数相同。
  • 我想知道为什么这被否决了?

标签: c# readability


【解决方案1】:

不完全确定你要做什么,但由于你使用的是基类型继承链,你可能会选择做类似的事情

interface ICreature
{
    bool IsAwesome { get; set; }
    int GetScalar();
}

abstract class Creature : ICreature
{
    public bool IsAwesome { get; set; }
    public virtual int GetScalar()
    {
        return 160;
    }
}

class SpecialCreature : Creature
{
    public override int GetScalar()
    {
        return this.IsAwesome ? 700 : 500;
    }
}

class NotSoNormalCreature : Creature
{
    public override int GetScalar()
    {
        return this.IsAwesome ? 450 : 280;
    }
}

// more ICreatures...

这将允许您让该生物实现自己的逻辑来确定标量,并且您的消费代码可能会失去关心的复杂性。

ICreature creature = GetCreatureFromSomewhere();
int scalar = creature.GetScalar();

【讨论】:

  • 我喜欢你的想法,但是,这个标量是用于计算特定掉落的机会,而将公式遍布整个地方的想法将使未来更难跟踪或更改
  • @Nico,对不起,您觉得它不能解决您的特定需求。但是,它可能对处于某种类似情况的人有所帮助,并且您可能会在其他地方发现这种模式很有用,如果不是在这里。
  • 是的,这就是我提到我喜欢它的原因,尽管这不是我在这种特殊情况下寻找的解决方案。
【解决方案2】:

这里不是你需要的,但是当条件可以解析为 Or's 或 And's 的列表时,我使用 Extension 方法来实现这种链式方法。

有点像

if (true.IfOr(condition1 == a, condition2 == b) 
{ 
  something(); 
}

那么扩展方法就很简单了:

public static bool IfOr(this bool result, params bool[] tests)
{
  foreach (bool test in tests)
    if (!test)
      return !result;
  return result;
}

另一种可行的方法,虽然它可能不是非常优化,但它是利用 .net 中的 Predicate 委托并定义一个方法列表来执行您的各个逻辑单元。然后,您可以用 lambda 替换嵌套的三元运算符。 抱歉,我手头没有这方面的代码示例。

最后,有时没有什么比一个好的旧 switch 语句更好的了。我相信 .Net 倾向于将这些编译为跳转表,因此只要您首先按最可分割的测试安排测试,那么您实际上可以获得相当高性能和可读的代码。而且它是可维护的,而不是用技巧隐藏逻辑或实现。

【讨论】:

    【解决方案3】:

    我认为真正的问题是您正在硬编码“配置数据”。如果你在哪里说,撕掉那些“设置”并将它们放入 XML 配置文件中,那么整个混乱不会消失吗?

    在您调整各种配置以使游戏更具可玩性之前,这似乎也有点过头了……单独的配置文件可让您轻松玩(和还原)。


    编辑:

    顺便说一句,我会将嵌套的三元语句格式化如下...以使其更具可读性。

    int scalar =
      creature is SpecialCreature
      ? creature.IsAwesome ? 700 : 500
      : creature is NotSoNormalCreature
        ? creature.IsAwesome
          ? creature is IGreatCreature ? 450 : 280
          : 240
        : creature.IsAwesome
          ? creature is IGreatCreature ? 300 : 200
          : 160
    ;
    

    干杯。基思。

    【讨论】:

    • 我为什么要使用 xml?这些是静态的,只是物品掉落的公式,而不是与生物相关的配置值。 -1
    【解决方案4】:

    这就是我重新编写代码并使其可读的方式

    // Original code spread apart
    int scalar = creature is SpecialCreature ? (
        creature.IsAwesome ? 700 : 500
    ) : (
        creature is NotSoNormalCreature ? (
            creature.IsAwesome ? (
                creature is IGreatCreature ? 450 : 280
            ) : 240
        ) : (
            creature.IsAwesome ? (
                creature is IGreatCreature ? 300 : 200
            ) : 160
        )
    );
    
    // Readable code with hybrid if() and ? :
    if (creature is SpecialCreature)
    {
        scalar = creature.IsAwesome ? 700 : 500;
    }
    else if (creature is NotSoNormalCreature)
    {
        if (creature.IsAwesome)
        {
            scalar = creature is IGreatCreature ? 450 : 280;
        }
        else
        {
            scalar = 240;
        }
    }
    else
    {
        if (creature.IsAwesome)
        {
            scalar = creature is IGreatCreature ? 300 : 200;
        }
        else
        {
            scalar = 160;
        }
    }
    

    如果可能,我确实建议在每个类中移动此计算,并覆盖不同的分支。

    【讨论】:

    • 你刚刚编辑了这个问题,看起来就像我的回答一样。太棒了!
    【解决方案5】:

    好旧的怎么样:

    if (creature is SpecialCreature)
    {
        scalar=getSpecialCreatureScalar(creature);
    }
    else if (creature is NotSoNormalCreature)
    {
        scalar=getNotSoNormalCreatureScalar(creature);
    }
    else
    {
        scalar=getScalar(creature);
    }
    

    ..然后

    int GetSpecialCreatureScalar(SpecialCreature creature)
    {
        return creature.IsAwesome ? 700 : 500;
    }   
    
    int GetNotSoNormalCreatureScalar(NotSoNormalCreature creature)
    {
        if (creature.IsAwesome)
        {
            return creature is IGreatCreature ? 450 : 280;
        }
        else
        {
            return 240;
        }
    }   
    
    int GetScalar(Creature creature)
    {
        if (creature.IsAwesome)
        {
            return creature is IGreatCreature ? 300 : 200;
        }
        else
        {
            return 160;
        }
    }  
    

    ..给出 if 的含义。打造不同的 IMO。

    【讨论】:

    • 为什么要这样命名函数?我会把第一个字母大写。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-11-28
    • 1970-01-01
    • 2013-10-16
    • 1970-01-01
    • 2011-09-07
    • 2016-04-06
    • 1970-01-01
    相关资源
    最近更新 更多