Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/296.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何使用反应式扩展与状态进行轮询?_C#_System.reactive_Rx.net - Fatal编程技术网

C# 如何使用反应式扩展与状态进行轮询?

C# 如何使用反应式扩展与状态进行轮询?,c#,system.reactive,rx.net,C#,System.reactive,Rx.net,关于使用Reactive()进行数据库轮询,已经有一个很好的问题 我有一个类似的问题,但有一个转折点:我需要在下一个请求中输入上一个结果的值。基本上,我想调查一下: interface ResultSet<T> { int? CurrentAsOfHandle {get;} IList<T> Results {get;} } Task<ResultSet<T>> GetNewResultsAsync<T>(int? pre

关于使用Reactive()进行数据库轮询,已经有一个很好的问题

我有一个类似的问题,但有一个转折点:我需要在下一个请求中输入上一个结果的值。基本上,我想调查一下:

interface ResultSet<T>
{
   int? CurrentAsOfHandle {get;}
   IList<T> Results {get;}
}

Task<ResultSet<T>> GetNewResultsAsync<T>(int? previousRequestHandle);

还请注意,此版本允许在等待下一次迭代时收集
消息resultset
(例如,我想也许我可以使用
扫描
将上一个结果集对象传递到下一次迭代)您的问题基本上归结为:有一个带有签名的
扫描功能:

IObservable<TAccumulate> Scan<TSource, TAccumulate>(this IObservable<TSource> source, 
     TAccumulate initialValue, Func<TAccumulate, TSource, TAccumulate> accumulator)
考虑到这一点,我们可以对其进行一些修改,以合并减少功能:

public static IObservable<TAccumulate> MyObservableScan<TSource, TAccumulate>(this IObservable<TSource> source,
    TAccumulate initialValue, Func<TAccumulate, TSource, IObservable<TAccumulate>> accumulator)
{
    return source
        .Publish(_source => _source
            .Take(1)
            .Select(s => accumulator(initialValue, s))
            .SelectMany(async o => (await o.LastOrDefaultAsync())
                .Let(m => _source
                    .MyObservableScan(m, accumulator)
                    .StartWith(m)
                )
            )
            .Merge()
        );
}

//Wrapper to accommodate easy Task -> Observable transformations
public static IObservable<TAccumulate> MyObservableScan<TSource, TAccumulate>(this IObservable<TSource> source,
    TAccumulate initialValue, Func<TAccumulate, TSource, Task<TAccumulate>> accumulator)
{
    return source.MyObservableScan(initialValue, (a, s) => Observable.FromAsync(() => accumulator(a, s)));  
}

//Function to prevent re-evaluation in functional scenarios
public static U Let<T, U>(this T t, Func<T, U> selector)
{
    return selector(t);
}

请注意,在测试中,我注意到如果累加器
任务
/
可观察
函数在源代码中花费的时间超过间隔,则可观察将终止。我不知道为什么。如果有人能纠正,我将不胜感激。

我发现有一个超负荷的
可观察。生成
,这基本上起到了作用。主要缺点是它不能与
async
一起工作

public static IObservable Generate(TState initialState、Func condition、Func iterate、Func resultSelector、Func timeSelector、IScheduler调度器)

我传入
null
作为初始状态。传入
x=>true
作为我的条件(无休止地轮询)。在
迭代
中,我根据传入的状态执行实际的轮询。然后在
timeSelector
中返回轮询间隔

因此:

var resultSets=Observable.Generate(
//初始(空)结果
新结果集(),
//无休止的投票(直到取消订阅)
rs=>正确,
//每次轮询迭代
rs=>
{
//从以前的结果(可能是初始结果)获取版本
int?previousVersion=rs.CurrentVersionHandle;
//但问题是:它不能与异步方法一起工作:(
MessageResultSet MessageResultSet=ReadLateStMessageAsync(当前版本)。结果;
返回消息resultset;
},
//我们只关心在结果集中吐出消息
rs=>rs.消息,
//轮询间隔
时间跨度从分钟(1),
//运行每个迭代的计划程序
TaskPoolScheduler.Default);
返回结果集
//将消息列表投影到序列中
.SelectMany(messageList=>messageList);

另一个小缺点是整个结果集将持续到下一次迭代。问题中的版本允许对“消息”部分进行垃圾收集,因为我们只需要“版本”。
IObservable<TAccumulate> Scan<TSource, TAccumulate>(this IObservable<TSource> source, 
     TAccumulate initialValue, Func<TAccumulate, TSource, IObservable<TAccumulate>> accumulator)
public static IObservable<TAccumulate> MyScan<TSource, TAccumulate>(this IObservable<TSource> source, 
    TAccumulate initialValue, Func<TAccumulate, TSource, TAccumulate> accumulator)
{
    return source
        .Publish(_source => _source
            .Take(1)
            .Select(s => accumulator(initialValue, s))
            .SelectMany(m => _source.MyScan(m, accumulator).StartWith(m))
        );
}
public static IObservable<TAccumulate> MyObservableScan<TSource, TAccumulate>(this IObservable<TSource> source,
    TAccumulate initialValue, Func<TAccumulate, TSource, IObservable<TAccumulate>> accumulator)
{
    return source
        .Publish(_source => _source
            .Take(1)
            .Select(s => accumulator(initialValue, s))
            .SelectMany(async o => (await o.LastOrDefaultAsync())
                .Let(m => _source
                    .MyObservableScan(m, accumulator)
                    .StartWith(m)
                )
            )
            .Merge()
        );
}

//Wrapper to accommodate easy Task -> Observable transformations
public static IObservable<TAccumulate> MyObservableScan<TSource, TAccumulate>(this IObservable<TSource> source,
    TAccumulate initialValue, Func<TAccumulate, TSource, Task<TAccumulate>> accumulator)
{
    return source.MyObservableScan(initialValue, (a, s) => Observable.FromAsync(() => accumulator(a, s)));  
}

//Function to prevent re-evaluation in functional scenarios
public static U Let<T, U>(this T t, Func<T, U> selector)
{
    return selector(t);
}
var o = Observable.Interval(TimeSpan.FromMinutes(1))
    .MyObservableScan<long, ResultSet<string>>(null, (r, _) => Methods.GetNewResultsAsync<string>(r?.CurrentAsOfHandle))
var resultSets = Observable.Generate<ResultSet<IMessage>, IEnumerable<IMessage>>(
   //initial (empty) result
   new ResultSet<IMessage>(),

   //poll endlessly (until unsubscription)
   rs => true,

   //each polling iteration
   rs => 
   {
      //get the version from the previous result (which could be that initial result)
      int? previousVersion = rs.CurrentVersionHandle;

      //here's the problem, though: it won't work with async methods :(
      MessageResultSet messageResultSet = ReadLatestMessagesAsync(currentVersion).Result;

      return messageResultSet;
   },

   //we only care about spitting out the messages in a result set
   rs => rs.Messages, 

   //polling interval
   TimeSpan.FromMinutes(1),

   //which scheduler to run each iteration 
   TaskPoolScheduler.Default);

return resultSets
  //project the list of messages into a sequence
  .SelectMany(messageList => messageList);