C # обещает зацикливание метода на неопределенное время - PullRequest
0 голосов
/ 25 февраля 2019

Я использую библиотеку C # Promises для проекта Unity, и я хочу вызывать блок кода обещания неопределенное время.Каждый раз, когда обещание выполнено, оно должно решить, будет ли оно вызвано снова или нет.Я нашел это JavaScript решение для ES6 в потоке JavaScript ES6 обещание цикла .

// JavaScript: Function calling itself upon resolution
(function loop(i) {
    if (i < 10) new Promise((resolve, reject) => {
        setTimeout( () => {
            console.log(i);
            resolve();
        }, Math.random() * 1000);
    }).then(loop.bind(null, i+1));
})(0);

Не могли бы вы помочь мне перенести эту идею в C #?

В настоящее время я формирую длинную последовательность обещаний, используя Then() в цикле for, и отклоняюсь, когда хочу выйти.Но это слабое решение.Вместо этого я хочу рассмотреть следующую итерацию только тогда, когда текущее обещание будет выполнено.

// C#: Forming the sequence before execution
var p = Promise.Resolved();
for (var i = 0; i < 100; i++)
{
    p = p.Then(outcome =>
    {
        if (shouldContinue)
        {
            // return a new Promise
        }
        else
        {
            // return Promise.Reject()
        }
    });
}

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

Пожалуйста, посмотрите мой ответ ниже для PromiseLooper класс.

Ответы [ 3 ]

0 голосов
/ 25 февраля 2019

Если бы мне понадобился цикл с асинхронными методами, я бы попытался найти «асинхронную поддержку Unity3d», такую ​​как this .

В противном случае вам нужно выполнить цепочку «повторить один раз меньше»похоже, как это делается в решении JS, которое вы показали.Я не уверен в точном синтаксисе (так как у меня нет Unity3d), но примерно он должен быть

Promise Loop(
      Func<Promise<TResult>> body, 
      Func<bool, TResult> shouldContinue,
      int iterations, Promise chain = null)
{
     chain = chain == null ?? Promise.Resolved() : chain;

     if (iterations == 0)
     { 
           return Promise.Resolved();
     }  

     Promise result = body().Then(outcome => 
     {
         if (shouldContinue(outcome))
             return Loop(body, iterations-1, result));
         else 
             return Promise.Rejected();
     });
}
0 голосов
/ 25 февраля 2019

Я придумал милый универсальный PromiseLooper.Этот класс позволяет

  • Предоставление Func<IPromise<T>> метода для цикла
  • Предоставление Func<T,bool> предиката для выхода из цикла
  • Цепочка другого обещания onResolve изloop
  • Перехват исключений, генерируемых в циклическом методе

Вот класс PromiseLooper:

// See https://stackoverflow.com/q/54859305/4112088
public class PromiseLooper<T>
{
    private readonly Func<IPromise<T>> loopingBody;
    private readonly Func<T, bool> continuePredicate;
    private readonly Exception exitException;

    // looper core method
    private IPromise<T> Loop(T previousOutcome)
    {
        return continuePredicate(previousOutcome)
            ? loopingBody().Then(Loop)
            : Promise<T>.Rejected(exitException);
    }

    // constructor
    public PromiseLooper(Func<IPromise<T>> loopingBody,
        Func<T, bool> continuePredicate)
    {
        this.loopingBody = loopingBody;
        this.continuePredicate = continuePredicate;
        // setting up a exit exception
        this.exitException = new Exception("LooperExit");
    }

    // looping starts when this called
    public IPromise StartLooping(T initialOutcome)
    {
        var loopPromise = new Promise();
        // reporting back loop status as a promise
        Loop(initialOutcome).Catch(e =>
        {
            if (e == exitException) loopPromise.Resolve();
            else loopPromise.Reject(e);
        });
        return loopPromise;
    }
}

Пример использования:

// where you create the looper and call StartLooping()
private void Start()
{
    var looper = new PromiseLooper<int>(GenerateRandomInt, IsNotFive);
    looper.StartLooping(0).Then(
        () => Console.WriteLine("Loop complete!"),
        e => Console.WriteLine($"Loop error! {e}"));
}

// the predicate that decides the end of the loop
private bool IsNotFive(int x)
{
    return x != 5;
}

// the method you want to loop!
private IPromise<int> GenerateRandomInt()
{
    var promise = new Promise<int>();
    //this could be any async time consuming call
    // that resolves the promise with the outcome
    LeanTween.delayedCall(1,
        () => promise.Resolve(Random.Range(0, 10))
    );
    return promise;
}
0 голосов
/ 25 февраля 2019

Сначала определите свою функцию для «затем» отдельно.Затем убедитесь, что ваша переменная обещания доступна из функции.И, наконец, установите в своей функции обещание. Вместо того, чтобы снаружи.

Это пример в VB.net.(не должно быть сложно перейти на c #)

class Test
    Dim p As RSG.Promise = RSG.Promise.Resolved
    Private Function AndThen() As RSG.Promise
    '//do something ...
        If True Then
            Threading.Thread.Sleep(10000)
            MsgBox("AndThen")
            '//setup next promise here.
            p = p.Then(AddressOf AndThen)
            Return p
        Else
            Return RSG.Promise.Rejected(New Exception)
        End If
    End Function
    Public Sub Test()
        '//our only external call of promise.then
        p.Then(AddressOf AndThen)
    End Sub
End Class
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...