паўтарыўшы функцыю ў C #, пакуль яна больш не кідае выключэнне

У мяне ёсць клас, які выклікае інтэрфейс SOAP і атрымлівае масіў дадзеных спіны. Аднак, калі гэты запыт часу чакання, ён выклікае выключэнне. Гэта добра. Тым не менш, я хачу, каб мая праграма спрабавала зрабіць гэты выклік яшчэ раз. Калі гэта раз, я б хацеў, каб працягваць рабіць гэты выклік, пакуль не ўдаецца. Як я магу гэта зрабіць?

Напрыклад:

try
{
   salesOrdersArray = MagServ.salesOrderList(sessID, filter);
}
catch
{
   ?? What Goes Here to FORCE the above line of code to rerun until it succeeds.
}
7
Павялічце час чакання, так што не кідае выключэнне?
дададзена аўтар ChaosPandion, крыніца
З усіх гэтых адказаў, а не адзін чалавек кажа вам, каб злавіць больш канкрэтнае выключэнне. Што рабіць, калі паспрабаваць блок змяшчае аб'екты ў непрацоўным стане, каб атрымаць salesOrderList ? Паўторная спроба ніколі не атрымаецца.
дададзена аўтар Marc, крыніца
Вы можаце проста выклікаць метад зноў з блока злавіць, <�я> АЛЕ </я> - тое, што адбываецца, калі служба не працуе на працягу доўгага перыяду часу? Вы хочаце спосаб запусціць рэкурсіўна на працягу 24 гадзін? Я б рэкамендаваў яго абмежаванне да зададзенага ліку спробаў.
дададзена аўтар Tim, крыніца

11 адказы

Вам проста трэба цыкл назаўсёды:

while (true)
{
    try
    {
        salesOrdersArray = MagServ.salesOrderList(sessID, filter);
        break;//Exit the loop. Could return from the method, depending
              //on what it does...
    }
    catch
    {
       //Log, I suspect...
    }
}

Звярніце ўвагу, што вы амаль напэўна не на самой справе бясконцы цыкл. Вы амаль напэўна ёсць максімальную колькасць спробаў, і, магчыма, толькі злавіць канкрэтныя выключэнні. Лоўля усе выключэння назаўжды можа быць жудасныя ... Уявіце сабе, калі salesOrderList (нетрадыцыйнае імя метаду, дарэчы) пралівае ArgumentNullException таму што ў вас ёсць памылка і фільтр роўна нулю ... вы сапраўды хочаце звязаць 100% ад вашага працэсара назаўжды?

16
дададзена
@ Цім: Я дадаваў пункт ніжэй - у асноўным код адказвае на пытанне прама, але пункт тлумачыць, што гэта, верагодна, не вельмі добрая ідэя :)
дададзена аўтар Jon Skeet, крыніца
@psyklopz: Вы паказваеце тып выключэння ў блоку злавіць: злавіць (SoapException) і г.д. Вы можаце паказаць некалькі розных тыпаў выключэнняў у некалькіх блоках ўлову.
дададзена аўтар Jon Skeet, крыніца
Калі я раблю такога роду рэчы, я паклаў у Спячы адпаведнай працягласці, так што ён не выкарыстоўвае 100% працэсарнага часу чакання для некаторых паслуг, каб вярнуцца ў Інтэрнэце. Я мог бы нават ўключаць у сябе абмежаваныя экспанентным (напрыклад, адтэрміноўкі TCP), так што ён хутка аднаўляецца пасля нязначных сеткавых збояў, але спрабуе адзін раз кожныя некалькі хвілін, калі паслуга ўніз на працягу доўгага перыяду часу.
дададзена аўтар Gabe, крыніца
+1 за канкрэтныя выключэння, я друкаваў свой каментар па гэтым пытанні падчас рэдагавання.
дададзена аўтар Marc, крыніца
Можа не так (патэнцыйна) звязаць сістэмныя рэсурсы і/або зрабіць прыкладанне выкліку адказваць на запыты? Не падобна, лепшае рашэнне для мяне ...
дададзена аўтар Tim, крыніца
Вы таксама можаце атрымаць бягучы час да і затым чакаць, пакуль дифф б/ш, то і зараз> 5 сек, а затым выйсці (ці колькі вы хочаце)
дададзена аўтар Mr Universe, крыніца
Я ведаю, я злавіць канкрэтныя выключэння, памылкі SOAP і г.д. Забыліся радасці перапынку, дзякуй.
дададзена аўтар psyklopz, крыніца

Калі вы не можаце змяніць тайм-аўт, ніжэй павінен працаваць. salesOrdersArray павінны быць ініцыялізаваны Null .

while(salesOrdersArray == null)
{
    try
    {
       salesOrdersArray = MagServ.salesOrderList(sessID, filter);
    }
    catch
    {
      //Log failure
    }
}
4
дададзена
+1: Мне падабаецца гэта крыху лепш, чым адказ Джона. Я думаю, што гэта робіць канчатковае ўмова цыклу больш відавочным.
дададзена аўтар Brian, крыніца

Гэта яго не Gernally добрага idead выкарыстоўваць выключэнне, як кіраванне патокам, але гэта будзе рабіць тое, што вы прасілі.

bool Caught = true;
while (Caught)
try
{
    salesOrdersArray = MagServ.salesOrderList(sessID, filter);
    Caught = false;
}
catch
{
    Caught = true;
}
1
дададзена

Я буду выкарыстоўваць <�моцны> транзакцыйных чарзе (MSMQ) для захоўвання выкліку службы. Цыкл будзе з чаргі паведамленняў і выклікаць службу ў TransactionScope, калі выклік ня паведамленне, як уяўляецца, усё яшчэ знаходзіцца ў чарзе. Таймаўт OV erall можа быць вызначаны шляхам дадання часу мінае ў паведамленні. Гэта рашэнне добра, калі вы сапраўды хочаце, надзейнае рашэнне, так як я здагадаўся, што выклік гэтай аперацыі мае вырашальнае значэнне.

1
дададзена

Вы павінны змясціць блок Try/злавіць ўнутры канструкцыі цыклу. Калі вы хочаце, каб не спажываць 100% ад вашага працэсара месца Thread.Sleep ў блоку злавіць, так што кожны раз, калі адбываецца выключэнне, ён будзе чакаць некаторы час, вызваляючы працэсар рабіць іншыя рэчы.

// iterate 100 times... not forever!
for (int i = 0; i < 100; i++)
{
    try {
       //do your work here;

        break;//break the loop if everything is fine
    } catch {
        Thread.Sleep(1000);
    }
}

Можна таксама пазначыць тып выключэння, так што толькі выключэнне таймаўту апрацоўваецца, і іншыя віды выключэнняў скразнымі.

// iterate 100 times... not forever!
for (int i = 0; i < 100; i++)
{
    try {
       //do your work here;

        break;//break the loop if everything is fine
    } catch (TimeOutException) {
        Thread.Sleep(1000);
    }
}

Варта адзначыць, што TimeoutException варта замяніць на рэальнае імя, за выключэннем ... Я не ведаю, калі гэта сапраўднае імя.

Таксама наладзіць час сну, дадзеныя ў мілісекундах і колькасць паўтораў, у выпадку, я прадставіў, 100 паўтораў 1000ms дае максімальную чаканне 1 хвіліну і 40 секунд, а таксама самому часу працы.

1
дададзена

спрабаваць

bool failed = false;
do {
 спрабаваць
 {
  salesOrdersArray = MagServ.salesOrderList(sessID, filter);
 }
 catch
 {
  failed = true;
 }
} while(failed);

Паводзіны вы пасля можа выклікаць бясконцы цыкл, калі гэта не атрымоўваецца, хоць ...

0
дададзена

Хоць я б не рэкамендаваў рабіць гэта для бясконцага ліку раз, вы маглі б зрабіць асобную функцыю з гэтай адной фразы:

void GoConnect()
{
    try
    {
        salesOrdersArray = MagServ.salesOrderList(sessID, filter);
    }
    catch
    {
        GoConnect();
    }
}
0
дададзена
bool repeat = true;
while (repeat)
{
    try
    {
       salesOrdersArray = MagServ.salesOrderList(sessID, filter);
       repeat = false;
    }
    catch
    {
    }
}
0
дададзена

Я прытрымлівацца гэтага ўзоры, каб вырашыць гэтую праблему:

    public void Send(String data, Int32 attemptNumber)
    {
        try
        {
            yourCodeHere(data);
        }
        catch (WebException ex)
        {
            if (attemptNumber > 0)
                Send(data, --attemptNumber);
            else
                throw new AttemptNumberExceededException("Attempt number exceeded!", ex);
        }
        catch (Exception ex)
        {
            //Log pourpose code goes here!
            throw;
        }
    }

Спрабуючы назаўжды, здаецца, не быць добрай ідэяй, як вы можаце ў канчатковым выніку бясконцы працэс. Калі вы думаеце, патрэбныя шмат спробаў, каб дасягнуць сваёй мэты толькі ўсталяваць велізарная колькасць тут.

Я асабіста думаю, што яго сэнс пачакаць некалькі мілісекунд або секунд пасля таго, як EAC спробы Thread.Sleep (1000); , перш чым callig Адправіць (дадзеныя); --- вы маглі б, напрыклад, выкарыстоўвайце зменную attempNumber для increse або паменшыць гэты час чакання, калі вы думаеце, што яго мудрае для вашага сцэнара.

0
дададзена
чаму я не павінен? Мой пункт гледжання такая ж, як Jon сподачках пад кодам ён напісаў
дададзена аўтар Renato Gama, крыніца
дзякуючы @asawyer не ведалі пра гэта, таму я адрэдагаваў мой адказ! гэта нармальна зараз?
дададзена аўтар Renato Gama, крыніца
ён мае рэальны сэнс ...! ніколі не думаў, што гэта так ... прабачце за стамляць вас, што цяпер?
дададзена аўтар Renato Gama, крыніца
<�Код> кідок экс Не рабі гэтага!
дададзена аўтар asawyer, крыніца
дададзена аўтар asawyer, крыніца
Дзве рэчы: 1- Вы амаль ніколі не хочаце, каб злавіць базавы клас выключэння, і калі вы робіце, гэта ў значнай ступені толькі для лесанарыхтовак, а затым кінуць зноў ІНГАЎ. 2 - Ніколі не кідайце базу Exception класа. Вы змушае спажывальных код у дрэнную практыку лоўлі Exception . Выкарыстоўвайце больш прыдатны падклас, або стварыць свой уласны.
дададзена аўтар asawyer, крыніца
Проста выдаткуйце трохі часу, каб прачытаць аб перадавой практыцы, і вы будзеце ў бізнэсе ў самыя кароткія тэрміны. Heres пару добрыя спасылкі: blogs.msdn. кім/б/ericlippert/Архіў/2008/09/10/& hellip; codeproject.com/KB/architecture/exceptionbestpractices.aspx
дададзена аўтар asawyer, крыніца
Аб вы маеце на ўвазе рэдагавання. Выглядае добра! :)
дададзена аўтар asawyer, крыніца

Паспрабуйце што-нешта накшталт гэтага:

var failed = true;
while (failed)
{
  try 
  {
    salesOrdersArray = MagServ.salesOrderList(sessID, filter); 
    failed = false;
  }
  catch
  {
  }
}

Змяніць: Wow! Вялікія розумы думаюць аднолькава! :)

0
дададзена
while(salesOrdersArray == null){

  try
  {
    salesOrdersArray = MagServ.salesOrderList(sessID, filter);
  }
  catch(salesOrderException e)
  {
     log(e.message);
  }
}

Гэта будзе працаваць вечна, і выкарыстоўвае выключэнні ў выглядзе завесы, якая павольна. Ці ёсць спосаб, вы можаце змяніць вашу функцыю, якая вяртае значэнне NULL, замест таго, каб кідаць выключэнне? Калі вы чакалі, што гэты заклік будзе рэгулярна церпяць няўдачу, не выкарыстоўвайце паспрабаваць/злавіць блок.

0
дададзена