2009-06-03 3 views
3

Я попытался изо всех сил создать пользовательский цикл while, но закончился тщетно. Неужели кому-то удалось создать пользовательский цикл while в NANT?Создание пользовательского цикла WHILE в NANT

+0

Можете ли вы описать проблему, которую вы пытаетесь решить с помощью цикла в то время? Возможно, другой способ. –

ответ

0

Без дополнительной информации, есть учебное пособие по созданию пользовательской задачи NAnt here.

Одна хорошая вещь о статье автор предлагает 2 средства отладки пользовательской задачи:

  1. Копирование сборки (и PDB-файл) в папку бин NAnt. Откройте свое решение в Visual Studio, которое содержит источник вашей задачи. Поместите свои контрольные точки. Перейдите к свойствам проекта и откройте страницу «Отладка». Измените режим Debug на Program и Start Application на путь к исполняемому файлу NAnt (например, C: \ Program Files \ NAnt \ bin \ NAnt.exe). Затем задайте аргументы рабочей директории и/или командной строки, чтобы NAnt собирал ваш файл сборки. Нажмите «Бег» и отпустите.

  2. Place System.Diagnostics.Debbugger.Break(); в вашем коде перед строкой, которую вы хотите разбить. Повторно скомпилируйте проект и скопируйте сборку (и pdb) в каталог NAnt bin. Когда вы запускаете свой скрипт NAnt, вы должны получить всплывающее окно с просьбой выбрать отладчик.

Существует еще один учебник here.

С другой стороны, можете ли вы выразить свою проблему с точки зрения foreach?

0

Я создал пользовательскую задачу самостоятельно. Но, похоже, есть некоторые проблемы с использованием вложенных циклов в NANT.

В основном я пытаюсь использовать вложенный цикл. Цикл while внутри foreach или foreach внутри другого foreach. Но в обоих случаях цикл выполняет текущую цель & цель, из которой вызывается текущая цель для каждой итерации, а не тела внутри второго цикла.

С уважением

Sarathy

+0

Вы опубликовали бы исчерпывающий минималистский пример кода и задач NAnt, которые могут продемонстрировать проблему? – JeffH

6

Вы можете создать пользовательскую задачу:

<target name="sample"> 
    <property name="foo.value" value="0"/> 
    <while property="foo.value" equals="0"> 
     <do> 
     <echo message="${foo.value}"/> 
     <property name="foo.value" value="${int::parse(foo.value) + 1}"/> 
     </do> 
    </while> 
    </target> 

    <script language="C#" prefix="directory"> 
    <code> 
     <![CDATA[ 
[TaskName("while")] 
public class WhileTask : TaskContainer 
{ 
    private TaskContainer _doStuff; 
    private string _propertyName; 
    private string _equals; 
    private string _notEquals; 

    [BuildElement("do")] 
    public TaskContainer StuffToDo 
    { 
     get 
     { 
      return this._doStuff; 
     } 
     set 
     { 
      this._doStuff = value; 
     } 
    } 

    [TaskAttribute("property")] 
    public string PropertyName 
    { 
     get 
     { 
      return this._propertyName; 
     } 
     set 
     { 
      this._propertyName = value; 
     } 
    } 

    [TaskAttribute("equals")] 
    public string Equals 
    { 
     get 
     { 
      return this._equals; 
     } 
     set 
     { 
      this._equals = value; 
     } 
    } 

    [TaskAttribute("notequals")] 
    public string NotEquals 
    { 
     get 
     { 
      return this._notEquals; 
     } 
     set 
     { 
      this._notEquals = value; 
     } 
    } 

    protected override void ExecuteTask() 
    { 
     while (this.IsTrue()) 
     { 
      this._doStuff.Execute(); 
     } 
    } 

    private bool IsTrue() 
    { 
     if (!string.IsNullOrEmpty(this.Equals)) 
     { 
      return this.Properties[this.PropertyName] == this.Equals; 
     } 
     return this.Properties[this.PropertyName] != this.NotEquals; 
    } 
} 
    ]]> 
    </code> 
    </script> 
1

Там довольно много способов вы можете сделать это. Я написал что-то похожее на Cao, которое вызывает свойство true, поэтому условие может быть таким сложным, как вам нравится, и если оно сделано динамически, значение оценивается каждым циклом, который удобен, когда вы вызываете функции, например. для проверки файла существует. Я также добавил простой перерыв и продолжение контроля. Он также может быть запущен как бесконечный цикл без атрибутов, которые могут быть полезны, когда вы хотите, чтобы многие условия выходили (в этом случае используйте «if» с break/continue или - в моем случае - я хотел запустить задачу до тех пор, пока он исключается, а затем обрабатывается с помощью failonerror или блока trycatch.

Вот немного Nant скрипт, который показывает два способа отсчета от 10:

<property name="greaterthanzero" value="${int::parse(count) > 0}" dynamic="true"/> 

<property name="count" value="10" /> 
<while propertytrue="greaterthanzero" > 
    <echo>CountDown = ${count}</echo> 
    <property name="count" value="${int::parse(count) - 1}" /> 
</while> 

<property name="count" value="10" /> 
<while> 
    <if test="${int::parse(count) > 0}" > 
    <echo>CountDown = ${count}</echo> 
    <property name="count" value="${int::parse(count) - 1}" /> 
    <continue/> 
    </if> 
    <break/> 
</while> 

А вот реальный пример мира я использую, чтобы ждать, пока файл блокировки не будет удален:

<property name="count" value="0" /> 
<property name="lockfileexists" value="${file::exists(lockfile)}" dynamic="true"/> 
<while propertytrue="lockfileexists" > 
    <sleep seconds="1" /> 
    <property name="count" value="${int::parse(count) + 1}" /> 
    <if test="${count == '15'}" > 
    <echo>Timed out after 15 seconds</echo> 
    <break/> 
    </if> 
</while> 

Вот код задачи:

<script language="C#" prefix="loops"> 
<code> 
    <![CDATA[ 

    public class LoopBreakException : Exception {} 
    public class LoopContinueException : Exception {} 

    [TaskName("break")] 
    public class BreakTask : Task 
    { 
     protected override void ExecuteTask() 
     { 
      throw new LoopBreakException(); 
     } 
    } 

    [TaskName("continue")] 
    public class ContinueTask : Task 
    { 
     protected override void ExecuteTask() 
     { 
      throw new LoopContinueException(); 
     } 
    } 

    [TaskName("while")] 
    public class WhileTask : TaskContainer 
    { 
     [TaskAttribute("propertytrue")] 
     public string PropertyName { get; set; } 

     protected bool CheckCondition() 
     { 
      if (!string.IsNullOrEmpty(PropertyName)) 
      { 
       try 
       { 
        return bool.Parse(Properties[PropertyName]); 
       } 
       catch (Exception ex) 
       { 
        throw new BuildException(string.Format("While Property '{0}' not found", PropertyName), Location); 
       } 
      } 
      //for infinite loops 
      return true; 
     } 

     protected override void ExecuteTask() 
     { 
      while (CheckCondition()) 
      { 
       try 
       { 
        ExecuteChildTasks(); 
       } 
       catch (LoopContinueException) 
       { 
        continue; 
       } 
       catch (LoopBreakException) 
       { 
        break; 
       } 
      } 
     } 
    } 
]]> 
</code> 

3

Вот еще один пример простой, но эффективной версии цикла while, реализованной в NAnt.

<?xml version="1.0"?> 
<project name="whiletask" xmlns="http://tempuri.org/nant-donotuse.xsd"> 

    <script language="C#" prefix="loop"> 
    <code> 
     <![CDATA[ 

    /// <summary> 
    /// A while loop task. Will continuelly execute the task while the <c>test</c> is <c>empty</c> 
    /// or evalutes to <c>true</c>. 
    /// </summary> 
    [TaskName("while")] 
    public class WhileTask : TaskContainer 
    { 
     private string _test; 
     private TaskContainer _childTasks; 

     /// <summary> 
     /// The expression to test each iteration. If empty, then always evalutes to true (i.e. infinite loop.) 
     /// </summary> 
     [TaskAttribute("test", ExpandProperties = false)] 
     public string Test 
     { 
      get { return _test; } 
      set { _test = NAnt.Core.Util.StringUtils.ConvertEmptyToNull(value); } 
     } 

     /// <summary> 
     /// Superficial to ensure the XML schema is rendered correctly for this task. It will get executed 
     /// if tasks exist within it. 
     /// </summary> 
     [BuildElement("do")] 
     public TaskContainer ChildTasks 
     { 
      get { return _childTasks; } 
      set { _childTasks = value; } 
     } 

     /// <summary> 
     /// Executes the while loop while the <c>test</c> evalutes to true or <c>test</c> is empty. 
     /// </summary> 
     protected override void ExecuteTask() 
     { 
      while (this.Test == null 
       || bool.Parse(Project.ExpandProperties(this.Test, this.Location))) 
      { 
       if (this._childTasks != null) 
       { 
        this._childTasks.Execute(); 
       } 
       else 
       { 
        base.ExecuteTask(); 
       } 
      } 
     } 
    } 

      ]]> 
    </code> 
    </script> 

    <property name="i" value="0" /> 
    <while test="${int::parse(i) &lt;= 10}"> 
    <echo message="${i}" /> 
    <property name="i" value="${int::parse(i)+1}" /> 
    </while> 

</project> 
5

глядя на список доступных в данный момент задач для NAnt, это выглядит как пока больше не поддерживается (http://nant.sourceforge.net/release/latest/help/tasks/)

Так что я думаю, что самый простой и эффективный способ, как сделать пользовательский, а цикл - рекурсия.

Так, например, что-то вроде этого:

<property name="count" value="120" /> 

<target name="wait">   
    <if test="${int::parse(count) > 0}" > 
     <property name="count" value="${int::parse(count) - 1}" /> 

     <call target="wait"/> 
    </if> 
</target> 

С уважением,

Marek

0

Вот один из способов написания цикла WHILE в NAnt, без каких-либо пользовательских задач или script элемента, используя failonerror="false" на петле foreach.

<property name="n" value="10000" /><!-- this would be inefficient if "n" is very large --> 
    <property name="i" value="0" /> 
    <foreach item="String" in="${string::pad-right(' ', int::parse(n), ',')}" delim="," property="val" failonerror="false" > 
     <if test="${int::parse(i) &gt; 3}"><!-- put our exit condition here --> 
      <fail message="condition met, exit loop early" /> 
     </if> 
     <echo message="i: ${i}" /> 
     <property name="i" value="${int::parse(i) + 1}" /> 
    </foreach> 

Результат выполнения цикла WHILE выше выглядит следующим образом. Следует отметить, что в связи с failonerror="false"fail вызов не завершает сценарий:

 [echo] i: 0 
    [echo] i: 1 
    [echo] i: 2 
    [echo] i: 3 
    [foreach] myscript.nant(24,18): 
    [foreach] condition met, exit loop early 

    BUILD SUCCEEDED - 1 non-fatal error(s), 0 warning(s) 

I на основе цикл WHILE выше о том, как я построить цикл, который является немного упрощенной версией кода выше:

 <property name="n" value="5" /> 
     <property name="i" value="0" /> 
     <foreach item="String" in="${string::pad-right(' ', int::parse(n), ',')}" delim="," property="val" > 
      <echo message="i: ${i}" /> 
      <property name="i" value="${int::parse(i) + 1}" /> <!-- increment "i" --> 
     </foreach> 

выход из цикла FOR выглядит следующим образом:

 [echo] i: 0 
    [echo] i: 1 
    [echo] i: 2 
    [echo] i: 3 
    [echo] i: 4 

BUILD SUCCEEDED 
+0

Я включил код цикла FOR, так как кто-то, кто посещает этот вопрос, может искать такую ​​вещь. – Boinst

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