简体   繁体   中英

C# Code readability issue

        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));

how should I write that code to make it more readable?

I thought of just building the ifs, but then I thought how about making some kind of "ConditionFactory"? Would that make any sense, or is it just too intricate for such a simple task?

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;
    }
}

Not sure entirely what you're going for, but since you are using a base type inheritance chain, you might elect to do something like

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...

Which would allow you to have the creature implement its own logic for determining the scalar, and your consuming code can lose the complication of caring .

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

It's not quite what you need here but I use an Extension method to implement this sort of chain method when the condition can be resolved to a list of Or's or And's.

Something like

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

the extension method is then quite easy:

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

Another method that can work although it may not be very optimal is to make use of the Predicate delegate in .net and define a list of methods that perform your individual units of logic. You can then replace your nested tertiary operators with a lambda. I don't have the code sample of this to hand though, sorry.

Lastly though, sometimes there is just nothing better than a good old switch statement. I believe that.Net tends to compile these as jump tables so as long as you arrange your test by the most divisible ones first, then you can actually get quite performant and readable code. And it's maintainable instead of hiding logic or implementation with tricks.

I think the real issue is that you're hardcoding "configuration data". If you where to say, rip those "settings" out and put them into an XML config file then does not that whole mess disappear?

That too may seem like overkill, until you come to tweak your various configs, to make the game more playable... a seperate config FILE allows you to play (and revert) easily.


EDIT:

By the way, I would format that nested terniary statement as below... to make it more readable.

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
;

Cheers. Keith.

This is how I re-did the code and made it readable

// 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;
    }
}

I do want to recommend moving this calculation inside each class if possible, with overrides for the different branches.

How about good old:

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

..And then

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;
    }
}  

..Gives the if's a meaning. Makes a different IMO.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM