Вы действительно должны попытаться создать наблюдаемое так, чтобы оно моделировало выбор взлета или посадки в любое время - так же, как это делает пользователь дрона.
Это становится довольно просто, есливы создаете свой код следующим образом:
public class Drone
{
public Drone()
{
this.Altitude = ...
}
private bool _isLanding = true;
private Subject<bool> _isLandings = new Subject<bool>();
public bool IsLanding
{
get => _isLanding;
set
{
_isLanding = value;
_isLandings.OnNext(value);
}
}
public double BaseAltitude { get; set; } = 100.0;
public IObservable<double> Altitude { get; }
}
Каждый раз, когда IsLanding
изменяется, частное _isLandings
запускает значение, которое можно использовать для изменения режима дрона.
Теперьопределение Altitude
начинается с этого базового шаблона:
this.Altitude =
_isLandings
.Select(x => x ? landing : takeOff.Concat(cruise))
.Switch()
.StartWith(altitude);
Использование .Switch()
здесь является ключевым.Всякий раз, когда _isLandings
выдает значение, переключатель выбирает между посадкой или взлетом.Это становится единственной наблюдаемой, которая реагирует на повышение или понижение.
Полный код выглядит следующим образом:
public class Drone
{
public Drone()
{
var altitude = 0.0;
var interval = TimeSpan.FromMilliseconds(200);
IObservable<double> landing =
Observable
.Interval(interval)
.TakeWhile(h => altitude > 0.0)
.Select(t =>
{
altitude -= 10.0;
altitude = altitude > 0.0 ? altitude : 0.0;
return altitude;
});
IObservable<double> takeOff =
Observable
.Interval(interval)
.TakeWhile(h => altitude < BaseAltitude)
.Select(t =>
{
altitude += 10.0;
altitude = altitude < BaseAltitude ? altitude : BaseAltitude;
return altitude;
});
IObservable<double> cruise =
Observable
.Interval(interval)
.Select(t =>
{
altitude = 10.0 * Math.Sin(t * 2.0 * Math.PI / 180.0) + BaseAltitude;
return altitude;
});
this.Altitude =
_isLandings
.Select(x => x ? landing : takeOff.Concat(cruise))
.Switch()
.StartWith(altitude);
}
private bool _isLanding = true;
private Subject<bool> _isLandings = new Subject<bool>();
public bool IsLanding
{
get => _isLanding;
set
{
_isLanding = value;
_isLandings.OnNext(value);
}
}
public double BaseAltitude { get; set; } = 100.0;
public IObservable<double> Altitude { get; }
}
Вы можете проверить это с помощью:
var drone = new Drone();
drone.Altitude.Subscribe(x => Console.WriteLine(x));
Thread.Sleep(2000);
drone.IsLanding = false;
Thread.Sleep(4000);
drone.IsLanding = true;