2016-06-01 4 views
1

У меня есть функция в DLL, которую я создал, которая выполняет команды SQL и возвращает файл пути из того места, где они были выполнены, количество команд с ошибками и количеством команд, выполненных успешно всего в 3 позиции. массив. Проблема заключается в том, что он возвращается только в том случае, когда заканчивается конец foreach, который позволит мне представить только текстовое поле в форме последнего исполняемого файла, и мне нужно показать путь к файлу, когда они будут выполнены.Как вернуть значение из функции, но сохранить функцию «живой» C#

Мне нужен способ, чтобы вернуть массив Каждый раз, когда Foreach итерацию, но сохраняющий> функцию живых, так что выполняет все остальные команды в следующих> файлах, это функция:

public string[] ExecuteCommands(string Directoria, CdpsiUpdateSql Updater, CdpsiUpdateSqlparser parser, string Log) 
     { 

      string[] numArray1 = new string[3]; 
      List<string> list = ((IEnumerable<string>)Directory.GetFiles(Directoria, "*.sql", SearchOption.TopDirectoryOnly)).Select(f => 
      { 
       string[] strArray = Path.GetFileName(f).Split('_'); 
       int result; 
       if (strArray.Length < 1 || !int.TryParse(strArray[0], out result)) 
        result = -1; 
       var data = new 
       { 
        File = f, 
        Version = result 
       }; 
       return data; 
      }).Where(f => f.Version > -1).OrderBy(f => f.Version).Select(f => f.File).ToList<string>(); 
      foreach (string str in list) 
      { 
       int[] numArray2 = this.ExecuteCommand(parser.Parser(str), Updater, str, Log); 
       int Certos = Convert.ToInt32(numArray1[0]); 
       int Errados = Convert.ToInt32(numArray1[1]); 
       Certos += numArray2[0]; 
       Errados += numArray2[1]; 
       numArray1[0] = Certos.ToString(); 
       numArray1[1] = Errados.ToString(); 
       numArray1[2] = str; 

      } 
      return numArray1; 
     } 

Любая помощь будет высокоочищенного aprecciated, спасибо


используя выход?

public IEnumerable<string []> ExecuteCommands(string Directoria, CdpsiUpdateSql Updater, CdpsiUpdateSqlparser parser, string Log) 
     { 

      string[] numArray1 = new string[3]; 
      List<string> list = ((IEnumerable<string>)Directory.GetFiles(Directoria, "*.sql", SearchOption.TopDirectoryOnly)).Select(f => 
      { 
       string[] strArray = Path.GetFileName(f).Split('_'); 
       int result; 
       if (strArray.Length < 1 || !int.TryParse(strArray[0], out result)) 
        result = -1; 
       var data = new 
       { 
        File = f, 
        Version = result 
       }; 
       return data; 
      }).Where(f => f.Version > -1).OrderBy(f => f.Version).Select(f => f.File).ToList<string>(); 
      foreach (string str in list) 
      { 
       int[] numArray2 = this.ExecuteCommand(parser.Parser(str), Updater, str, Log); 
       int Certos = Convert.ToInt32(numArray1[0]); 
       int Errados = Convert.ToInt32(numArray1[1]); 
       Certos += numArray2[0]; 
       Errados += numArray2[1]; 
       numArray1[0] = Certos.ToString(); 
       numArray1[1] = Errados.ToString(); 
       numArray1[2] = str; 
       yield return numArray1; 
      } 
      //return numArray1; 
     } 
+0

Прежде всего сделать класс для хранения результата (класс 'CommandResult {общественные ИНТ Certos; общественности int Errados, public string Command;} '), а затем вернуть' IEnumerable ', а затем опубликовать его в Code Review, есть некоторые интересные вещи, которые вы можете сделать, чтобы сделать этот код более удобным для чтения. –

+0

@AdrianoRepetti можете ли вы добавить пример? Если я вернусь, IEnumerable не закончит функцию, когда достигнет возврата? – LikeIfYouCaredAboutMyName

+0

Да, но вы сохраняете результаты в 'List ' или используете синтаксис 'yield return'. –

ответ

2

В первом я бы определил лучший тип для результата, как, что:

public struct Result 
{ 
    public string File; 
    public int Errors; 
    public int Successes; 
} 

И тогда вы можете добавить параметр IProgress<T> к вашему методу dll: И использовать это как дополнительный аргумент для вашего метода dll:

public void ExecuteCommands(string Directoria, CdpsiUpdateSql Updater, CdpsiUpdateSqlparser parser, string Log, IProgress<Result> progress) 
{ 
    //... your code 

    foreach (string str in list) 
    { 
     int[] numArray2 = this.ExecuteCommand(parser.Parser(str), Updater, str, Log); 
     // your code 

     Result result = new Result 
     { 
      File = str, 
      Error = Errados, 
      Successes = Certos 
     }; 
     progress.Report(result); 
    } 
} 

На сайте вызывающих создать экземпляр Progress<T> подобные:

Progress<Result> progress = new Progress<Result>(HandleProgress); 
ExecuteCommands(Directoria, Updater, parser, Log, progress); 

И реализовать HandleProgress метод так:

private void HandleProgress(Result result) 
{ 
    /* use the values in result to update your UI */ 
    Refresh(); // refresh the controls you updated 
} 

Примечания однако, что ваш ExecuteCommands пробегает синхронно. Таким образом, ваш поток пользовательского интерфейса блокируется, и изменения в элементах управления не отображаются непосредственно. Поэтому я добавил, что оператор Refresh(), но его точное внедрение немного зависит от элементов управления, которые вы собираетесь обновить.

Подход yield/IEnumerable тоже хороший. Но я все же предлагаю правильный тип Result. Потребители вашего метода никогда не узнают, какая информация содержится в этом массиве строк. И проблема с заблокированным потоком пользовательского интерфейса будет одинаковой.

+0

@LikeIfYouCaredAboutMyName да, это также хороший подход. Но я все же предлагаю определить правильный тип «Результат» вместо использования строкового массива. –

+0

Im действительно путают с использованием вашего метода, Im относительно новым для этой srry: \ 'Прогресс прогресс = новый Прогресс (результат =>/* делаем что-то с результатом * /);' это будет объявлено вне функции в основной форме правильной? – LikeIfYouCaredAboutMyName

+0

это только «отчетность», когда конец foreach заканчивается, отображается только информация для последнего выполненного файла: \ – LikeIfYouCaredAboutMyName

0

Вы можете переместить оператор возврата в цикл по каждому элементу и использовать выход

foreach (string str in list) 
      { 
       int[] numArray2 = this.ExecuteCommand(parser.Parser(str), Updater, str, Log); 
       int Certos = Convert.ToInt32(numArray1[0]); 
       int Errados = Convert.ToInt32(numArray1[1]); 
       Certos += numArray2[0]; 
       Errados += numArray2[1]; 
       numArray1[0] = Certos.ToString(); 
       numArray1[1] = Errados.ToString(); 
       numArray1[2] = str; 

       yield return numArray1; 
      } 
+0

Даже если он решает проблему немедленного OP ... Я бы не предложил возвращать числа в виде строк только потому, что одна из них - это строка. Если вы опубликуете ответ, я бы рассмотрел несколько проблем этого кода (и я бы добавил некоторые пояснения к предлагаемому решению ...) –

+0

@AdrianoRepetti Я только добавил числа в виде строк, потому что мне нужно было сразу вернуть все значения , Я на самом деле думал, что я вернусь к структуре, не могли бы вы увидеть мой обновленный вопрос? – LikeIfYouCaredAboutMyName

+0

@LikeIfYouCaredAboutMyName Решение René довольно хорошо. Вы можете решить использовать или не функцию обратного вызова (возвращаясь вместо IEnumerable), но дело в том, чтобы ввести структуру. Не только из-за правильного ввода (int вместо строки), а потому, что при доступе к результату [1] вы не можете видеть (в точке вызова), какое поле вы читаете (более того, вы можете сделать его доступным только для чтения, если хотите). Когда у вас есть рабочее решение, я настоятельно рекомендую опубликовать его на Code Review, и вы получите много полезных советов! –

0

Просто, чтобы предоставить вам несколько альтернатив.Вы можете попробовать использовать делегат/лямбда

public void ExecuteCommands(string Directoria, CdpsiUpdateSql Updater, CdpsiUpdateSqlparser parser, string Log, Action<int[]> getResults) 
{ 

    string[] numArray1 = new string[3]; 
    List<string> list = ((IEnumerable<string>)Directory.GetFiles(Directoria, "*.sql", SearchOption.TopDirectoryOnly)).Select(f => 
    { 
     string[] strArray = Path.GetFileName(f).Split('_'); 
     int result; 
     if (strArray.Length < 1 || !int.TryParse(strArray[0], out result)) 
      result = -1; 
     var data = new 
     { 
      File = f, 
      Version = result 
     }; 
     return data; 
    }).Where(f => f.Version > -1).OrderBy(f => f.Version).Select(f => f.File).ToList<string>(); 
    foreach (string str in list) 
    { 
     int[] numArray2 = this.ExecuteCommand(parser.Parser(str), Updater, str, Log); 
     int Certos = Convert.ToInt32(numArray1[0]); 
     int Errados = Convert.ToInt32(numArray1[1]); 
     Certos += numArray2[0]; 
     Errados += numArray2[1]; 
     numArray1[0] = Certos.ToString(); 
     numArray1[1] = Errados.ToString(); 
     numArray1[2] = str; 

     //new code 
     if(getResults!=null) 
     { 
      getResults(numArray1); 
     } 
    } 

} 

Использование в основной вызов тогда будет:

int totalResults=0; 
Action<int[]> doSomething = (results)=> 
    { 
     //do some work whenever results is returned, e.g 
     totalResults+=results.Sum(); 
    }; 
ExecuteCommands(directoria, parser, updater, log, doSomething); 
+0

Но будет ли это обновлять значения пользовательского интерфейса или пользовательский интерфейс будет заблокирован и будет обновляться только в конце? Я запустил функцию в задаче, чтобы сделать ее асинхронной, настолько удачной, но у меня возникла проблема. http://stackoverflow.com/questions/37588186/values-resetting-back-to-zero-after-task-is-completed-c-sharp – LikeIfYouCaredAboutMyName

+0

Я посмотрел на ваши другие qns. Я думаю, что ваша проблема может заключаться в том, что вы обновляете свой пользовательский интерфейс в задаче/потоке, что может привести к появлению условий гонки, потому что основной поток пользовательского интерфейса также может выполнять обновления. Позвольте мне сделать несколько тестов и вернуться к вам через пару часов –

+0

большое вам спасибо, Im действительно проиграл на этом. Я уже пробовал все, что мог запомнить – LikeIfYouCaredAboutMyName

Смежные вопросы