Рефакторинг коллекции операторов IF, содержащих два аргумента

На данный момент у меня есть семь операторов if, которые напоминают следующий код:

if(hit.collider.gameObject.tag == "Colour1" && start_time > look_at_time)
{
    new_colour1.ChangeObjectMaterialColour(hit.collider.gameObject.renderer.material.color);

   var colums = GameObject.FindGameObjectsWithTag("column");
   foreach( GameObject c in colums)
    c.GetComponent<MeshRenderer>().materials[1].color = new_colour1.orignalMaterial;
}


else if(hit.collider.gameObject.tag == "Colour2" && start_time > look_at_time)
{
    new_colour2.ChangeObjectMaterialColour(hit.collider.gameObject.renderer.material.color);
    var colums = GameObject.FindGameObjectsWithTag("column");
    foreach( GameObject c in colums)
       c.GetComponent<MeshRenderer>().materials[1].color = new_colour2.orignalMaterial;
}

Каждое утверждение занимает примерно 6 строк кода, занимает много места и может быть немного сложным для чтения. То, что я хочу сделать, это найти способ пересмотреть это так, чтобы мой код был немного менее громоздким и не занимал слишком много места.

Я думал об изменении своей коллекции операторов if в оператор switch, но обнаружил, что операторы switch не могут обрабатывать два аргумента, как у меня выше. Если есть какой-то другой способ, которым я могу пересмотреть мой код, но сохранить ту же функциональность, или я застрял в моей коллекции операторов if?

редактировать

Обновлено, чтобы содержать два из моих 7 утверждений. Пожалуйста, обратите внимание, я пытаюсь уменьшить количество утверждений IF или найти более умный способ их выполнения. Я не хочу добавлять дополнительные строки кода или операторы if.

2 ответа

Решение

Спасибо за обновление вашего кода, теперь мы можем начать смотреть на то, что дублируется. Например, единственное различие между двумя блоками кода - строка "Color1" а также "Color2" в операторе if и переменной new_colour1 который заменен на new_colour2,

Отсюда я бы предложил что-то вроде следующего:

//This should be declared once - e.g. class level not method level.
var colorDict = new Dictionary<string, [new_color_type]> 
                    {{"Colour1", new_colour1}, {"Colour2", new_colour2}};

[new_color_type] newColor;
if(start_time > look_at_time && colorDict.TryGetValue(
        hit.collider.gameObject.tag,
        out newColor))
{
   newColor.ChangeObjectMaterialColour(
                            hit.collider.gameObject.renderer.material.color);

   var colums = GameObject.FindGameObjectsWithTag("column");
   foreach( GameObject c in colums)
      c.GetComponent<MeshRenderer>().materials[1].color =
                                                    newColor.orignalMaterial;
}

Честно говоря, я считаю, что наиболее удобочитаемым и понятным в вашем случае является просто переместить логику блоков if в функции:

  if(hit.collider.gameObject.tag == "Colour1" && start_time > look_at_time)
    {
        DoTheThing(new_colour1);
    }
if(hit.collider.gameObject.tag == "Colour2" && start_time > look_at_time)
    {
        DoTheThing(new_colour2);
    }
//and so on



 void DoTheThing(MyType newColour)
  {
 newColour.ChangeObjectMaterialColour(hit.collider.gameObject.renderer.material.color);
      var colums = GameObject.FindGameObjectsWithTag("column");
       foreach( GameObject c in colums)
        c.GetComponent<MeshRenderer>().materials[1].color = newColour.orignalMaterial;
    }

Что касается использования switch Вы, конечно, можете сделать что-то вроде этого:

switch(hit.collider.gameObject.tag)
{
  case "Colour1":
      if (start_time>look_at_time)
      {
        //do something
      }
      else if (start_time<look_at_time)
      {
        //something else
      }
      else
      {
         //they are equal, etc, etc
      }
    break;
case "Colour2":
  //and so on
}

или если все блоки if делают одно и то же сравнение между start_time а также look_at_time тогда вы можете инвертировать его:

enum TimeDifference
{
   LessThan,Equal,GreaterThan
}
//just one way to get a constant switchable value, not necessarily the best
var diff = TimeDifference.Equal;
if (start_time>look_at_time) {diff=TimeDifference.LessThan}
else if (start_time<look_at_time) {diff=TimeDifference.GreaterThan}

switch(diff)
{
  case TimeDifference.LessThan:
     switch(hit.collider.gameObject.tag)
     {
       case "Colour1":
         //do something for Colour1
        break;   
        case "Colour2":
         //do something for Colour2
        break;
      }//end switch Colour
     break;
  case TimeDifference.GreaterThan
    switch(hit.collider.gameObject.tag)
     {
       case "Colour1":
         //do something for Colour1
        break;   
        case "Colour2":
         //do something for Colour2
        break;
      }//end switch Colour
     break;  
   default:
    //nested switch for Colour in the == case, you get the idea.
}

хотя удобочитаемость любого из вышеперечисленного по сравнению с несколькими красиво отформатированными и отдельными if блоки очень спорны.

Другой подход заключается в использовании Dictionary<string,Action<int,int>>: (при условииstart_time а также look_at_time оба intы и вся ваша логика как-то их вовлекает)

var Actions = new Dictionary<string,Action<int,int>>();
Actions.Add("Colour1",(s,l)=>{
 if (start_time>look_at_time)
          {
            //do something
          }
          else if (start_time<look_at_time)
          {
            //something else
          }
          else
          {
             //they are equal, etc, etc
          }

});

и тогда ваш основной код становится 1 строкой:

Actions[hit.collider.gameObject.tag](start_time,look_at_time);

И я уверен, что есть еще много способов изменить этот код.

Другие вопросы по тегам