尝试查找由多个参数确定的值时,如何避免进行大量的if-else检查?

时间:2018-08-18 23:18:41

标签: c# refactoring

我的函数有一项工作:返回一个简单的int索引。但是,为了“计算”该索引,它考虑了一些参数(在我的情况下为3,但为简单起见,在此示例中,我将使用2个参数)。我的函数看起来像这样:

int calculateIndex(int param1, int param2)

现在,它目前是如何工作的?它是在“层”中进行的。首先,它检查什么是param1。一旦确定,它将开始检查param2是什么值,依此类推。像这样:

if(param1 == 0)
{
    if(param2 == 0)
    {
        // Return some value.
    }
    else if(param2 == 1)
    {

    }
    else
    {

    }
}
else if(param1 == 1)
{
    if(param2 == 3)
    {

    }
    else
    {

    }
}
else
{
    if(param2 == 4)
    {

    }
    else if(param2 == 5)
    {

    }
    else if(param2 == 6)
    {

    }
    else if(param2 == 7)
    {

    }
    else
    {

    }
}

需要注意的重要一点是,param1的每种情况都可以有任意数量的if-elses。例如,如果param2为0,则param1可能有3种情况。但是,如果param2为1,则param1有2种情况,为param23

如果这一切都没有道理,让我给您举一个实际的例子。考虑以下功能:

else

void uselessFunction(int biome, int element) uselessFunctionbiome索引为参数,并根据输入显示适当的消息。

element

现在,该示例相当简短,但是如您所见,只有2个生物群落和几个块,此代码已经相当长。想象一下有20个生物群落的情况,每个生物群落都有10-15个可能出现在其上的方块。这会导致难以置信的长时间执行简单任务的功能,我需要一种更好的方法来设计该功能。怎么样?

3 个答案:

答案 0 :(得分:7)

您想要的技术称为“表驱动编程”。您将建立一系列包含您感兴趣的数据的“表”,然后进行表查找,而不是执行if-else系列。

由于您的元素表只是确定-不作决定,因此您甚至不需要字典;只需一组即可:

var biomeTable = new Dictionary<Biome, HashSet<Element>>()
{
  { Forest, new HashSet<Element>() { Grass, Water }},
  { Desert, new HashSet<Element>() { Sand }}
};

现在您的代码是:

if (biomeTable.ContainsKey(biome)) 
{
  if (biomeTable[biome].Contains(element))
    Console.WriteLine($"The {biome} contains {element}.");
  else
    Console.WriteLine($"The {biome} does not contain {element}.");
} 
else
   Console.WriteLine($"Invalid biome {biome}.");

看看情况如何?逻辑只是两个if-thens,不如生物群系/元素组合那么多。信息进入数据结构,而不进入代码结构。

通过这种方式,您可以将生物群系和元素放入配置文件中,并从文件中解析它们,构建字典并根据需要动态设置。

答案 1 :(得分:2)

您的夫妻在条件字典中使用Tuple作为复合键。

在下面的示例中,每个Dictionary项的值都是一个字符串(如您的示例中,消息是唯一的区别因素)。

但是,它也可以是实现接口的类型或类型实例,例如IBiomeElementLogic,并且每个键都有不同的实现。

这将是Inversion of Control的一种形式。

enum Biome
{
    Forest = 1,
    Desert = 2
}

enum Element
{
    Grass = 1,
    Water = 2,
    Sand = 3
}

static readonly Dictionary<(Biome, Element), string> Conditions = new Dictionary<(Biome, Element), string>
{
    { (Biome.Forest, Element.Grass) , "There is grass in the forest." },
    { (Biome.Forest, Element.Water) , "There is water in the forest." },
    { (Biome.Desert, Element.Sand) , "There is sand in the desert." }
};

static void Main(string[] args)
{
    UselessFunction(Biome.Forest, Element.Grass);
    UselessFunction(Biome.Forest, Element.Water);
    UselessFunction(Biome.Forest, (Element)100);
    UselessFunction(Biome.Desert, Element.Sand);
    UselessFunction(Biome.Desert, (Element)100);
    UselessFunction((Biome)100, Element.Grass);

    Console.Read();
}

static void UselessFunction(Biome biome, Element element)
{
    var key = (biome, element);

    if (Conditions.ContainsKey(key))
    {
        Print(Conditions[key]);
    }
    else if (Enum.IsDefined(typeof(Biome), biome))
    {
        Print("Given element is invalid for this biome.");
    }
    else
    {
        Print("Given biome is invalid.");
    }
}

static void Print(string message)
{
    Console.WriteLine(message);
}

答案 2 :(得分:-1)

这项技术将帮助您简化方法中的逻辑。

class BiomeElement
{
    public BiomeElement(int biome, int element)
    {
        Biome = biome;
        Element = element;
    }

    public int Biome { get; }
    public int Element { get; }

    public bool IsForestGrass { get { return Biome == 1 && Element == 1; } }
    public bool IsForestWater { get { return Biome == 1 && Element == 2; } }
}