Адмова ад выкарыстання Гото

усё -        Я рэфактарынгу некаторыя стары код, і я шукаю спосабы, каб паменшыць (або, калі не ліквідаваць яго цалкам) выкарыстанне заявы GoTo. У мяне ёсць раздзел кода наступным чынам:

public void GetData()
{
  TryAgain:
      Foo foo = bar.GetData();

      if(foo == null)
      {
          bar.addItem("Test");
          goto TryAgain;
      }

      //Use the bar object
}

Замена яго наступным чынам:

public void GetData()
{
      Foo foo = bar.GetData();

      if(foo == null)
      {
          bar.addItem("Test");
          GetData();
          return;
      }

      //Use the bar object

}

Любыя думкі або лепшы спосаб справіцца з гэтым?

UPDATE

Перш за ўсё, гэта не мой фактычны код, я стварыў гэты фрагмент ў мэтах сцісласці. Далей, калі ласка, выкажам здагадку, што калі-то значэнне было дададзена ў бар, то аператар IF будзе прапушчана і секцыя кода будзе працягваць і выкарыстоўваць аб'ект бар. Я хачу стварыць толькі адзін метад, які спачатку правярае, каб пераканацца, што аб'ект бара не з'яўляецца нулявым, а калі няма, то працягнуць падножка пакінутай часткі кода ў метадзе. Выбачайце за бязладдзе.

2
Ваш рэфактарынгу ставіць абмежаванне на колькасць чэкаў, якія вы можаце зрабіць (да таго часу, StackOverflowException) у той час як першы будзе правяраць на нявызначаны тэрмін.
дададзена аўтар Austin Salonen, крыніца
Таму што вы вярнуцца да пачатку фрагмента кода ўмоўна; вы будзеце працягваць рабіць гэта зноў і зноў да таго часу, пакуль ўмова не выканана, а затым вы перастанеце вярнуцца да пачатку і проста скончыцца. Гэта ў значнай ступені <�я> вызначэнне з цыклу.
дададзена аўтар Servy, крыніца
Нягледзячы на ​​тое, што напісана з функцыяй нармальнага петлевой Гото замест, то першы код, які вяртаецца назад на сябе, такім чынам, гэта пятля.
дададзена аўтар Tim S., крыніца
@Servy другога прыкладу не зусім тое ж самае, што і выдаленне Гото і нічога не робячы, з-за гэтага: bar.addItem ( «Test») змяняе аб'ект. Калі гэты метад нічога не мяняе, а проста вяртаецца значэнне або зрабіў некаторыя праверкі і, магчыма, кінуць выключэнне ці нешта, то гэта было б эквівалентна нічога не робячы.
дададзена аўтар Tim S., крыніца
з'яўляецца Foo выкарыстоўваецца пасля таго, як праверка праходзіць паспяхова? Калі няма, то чаму б не проста , калі (bar.GetData() == NULL) {bar.AddItem (); bar.GetData (); } - чаму ёсць лакальны Foo і Гото наогул?
дададзена аўтар Eric Lippert, крыніца
з'яўляецца Foo выкарыстоўваецца пасля таго, як праверка праходзіць паспяхова? Калі няма, то чаму б не проста , калі (bar.GetData() == NULL) {bar.AddItem (); bar.GetData (); } - чаму ёсць лакальны Foo і Гото наогул?
дададзена аўтар Eric Lippert, крыніца
@MarkKram, не ўпэўнены, што калі б я атрымаў гэта права, але, калі ласка, знайсці абнаўленне адказу на выклік ст.
дададзена аўтар Andrei, крыніца
@MarkKram, не ўпэўнены, што калі б я атрымаў гэта права, але, калі ласка, знайсці абнаўленне адказу на выклік ст.
дададзена аўтар Andrei, крыніца
Я не разумею ваш каментар, чаму б мой першы прыклад пятля?
дададзена аўтар Mark Kram, крыніца
Глядзіце маё абнаўленне.
дададзена аўтар Mark Kram, крыніца
Чаму ўніз галасаваць «геній»?
дададзена аўтар Mark Kram, крыніца
Чаму ўніз галасаваць «геній»?
дададзена аўтар Mark Kram, крыніца

8 адказы

Выкарыстоўвайце , а пятля

public void GetData()
{
    Foo foo = bar.GetData();

    while (foo == null)
    {
        bar.addItem("Test");
        foo = bar.GetData();
    }
}

Update. If I understood your real purpose right:

public void GetData()
{
    Foo foo = bar.GetData();    
    if (foo == null)
    {
        bar.addItem("Test");
       //following the assumption
       //"once a value has been added to bar then the IF statement will be bypassed"
       //there is no need for another GetData call - bar object is in valid state now
    }

    //Use the bar object
}
9
дададзена

Выкарыстоўвайце , а пятля

public void GetData()
{
    Foo foo = bar.GetData();

    while (foo == null)
    {
        bar.addItem("Test");
        foo = bar.GetData();
    }
}

Update. If I understood your real purpose right:

public void GetData()
{
    Foo foo = bar.GetData();    
    if (foo == null)
    {
        bar.addItem("Test");
       //following the assumption
       //"once a value has been added to bar then the IF statement will be bypassed"
       //there is no need for another GetData call - bar object is in valid state now
    }

    //Use the bar object
}
9
дададзена

Вы ў асноўным апісваючы Await/асінхроннай шаблон, створаны ў .NET 4.5. Калі вы кантралюеце досыць кода, каб рэалізаваць гэты код у пытанне становіцца гэта:

// bar.addItem would need to be done in GetDataAsync if it is important
Foo foo = await bar.GetDataAsync();

Лепшы адказ у адваротным выпадку з'яўляецца падыход, а контур апісваецца @Andrei.

MSDN асінхронныя праграмаванне

3
дададзена
@ZachLeighton: Праблема эфектыўна не апісвае «апытанне пакуль» праблема, якая, як менавіта будзе рэалізаваны раствор/асінхроннай Await. Мы паняцця не маем, што bar.GetData </​​код> на самой справе робіць і не мае значэння, але мы ўсё роўна пакуль гэта не ня роўнае нулю; гэта значыць, мы <�я> чакаць да выкліку метаду "не ўдаецца."
дададзена аўтар Austin Salonen, крыніца
Гэта не мае нічога агульнага з чаканнем/асінхронным ..
дададзена аўтар Zach Leighton, крыніца
public void GetData()
{
    Foo foo;    
    while ((foo = bar.GetData()) == null)
        bar.addItem("Test");
}
3
дададзена
Я настойліва раю вам пазбягаць выкарыстання прысваення ва ўмоўных выразах; як правіла, прыводзіць да кода, гэта больш заблытаным для чытання, чым эквівалентныя refactors, якія выконваюць заданне за межамі ўмоўнай.
дададзена аўтар Servy, крыніца
У той час як я падзяляю вашу заклапочанасць, ў C# гэта адзіны спосаб, каб закіпяціць код да аднаго выкліку GetData. Тыя, з фонам у праграмаванні UNIX C распазнае гэты шаблон, так як ён звычайна выкарыстоўваецца для перабору патокаў, і шаблон часам рэкамендуецца ў C#, напрыклад, з StreamReader.ReadLine .
дададзена аўтар Frank Hileman, крыніца

Update based on your update, I might go with this code:

public void GetData()
{
    Foo foo = bar.GetData();

    if (foo == null)
    {
        bar.addItem("Test");
        foo = bar.GetData();

        Debug.Assert(foo != null, "Hey, I thought that would give me a value!");
    }

   //do something with foo
}
1
дададзена

Вы не карыстаецеся аб'ект Foo, так што вы можаце пазбавіцца ад яго.

public void GetData()
{
    while (bar.GetData() == null)
        bar.addItem("Test");

    //Use the bar object
}
1
дададзена
public void GetData()
{
  while(true)
 {
      Foo foo = bar.GetData();

      if(foo == null)
      {
          bar.addItem("Test");
      }
      else break;
 }
}
1
дададзена
public void GetData()
{
  while(true)
 {
      Foo foo = bar.GetData();

      if(foo == null)
      {
          bar.addItem("Test");
      }
      else break;
 }
}
1
дададзена