基于这些帖子:
Convert IReliableDictionary to IList
What is the most optimal method of querying a reliable dictionary collection
我应该能够使用Linq查询IReliableDictionary,但看起来这个接口不再实现IEnumerable,并且Linq扩展不可用。至少在Microsoft.ServiceFabric.Data.Interfaces程序集的5.0.0.0版中。
如果这是真的,那么搜索IReliableDictionary的最佳方法是什么?
答案 0 :(得分:10)
是的,我们确实从GA版本中的Reliable Collections中删除了IEnumerable。正如Allan T所提到的,Reliable Collections与常规.NET集合并不完全相同,即使它们代表相同的基础数据结构。您可能注意到的一个重大差异是所有操作都是异步的,因为锁定语义和I / O用于复制和磁盘读取。后者推动了删除IEnumerable的决定,因为它是严格同步的,我们不是。相反,我们现在使用IAsyncEnumerable,但它不支持完整的LINQ扩展方法集。
我们正在研究异步LINQ扩展方法,但与此同时,有两种方法可以使用IAsyncEnumerable。
Eli Arbel has async extension methods on Gist提供了System.Interactive.Async的桥梁以及Select,SelectMany和Where的异步实现。
或者你可以wrap IAsyncEnumerable in a regular IEnumerable简单地用同步方法包装异步调用,这将再次为你提供完整的LINQ扩展方法。然后,您可以在常规LINQ查询中使用扩展方法:
using (ITransaction tx = this.StateManager.CreateTransaction())
{
var x = from item in (await clusterDictionary.CreateEnumerableAsync(tx)).ToEnumerable()
where item.Value.Status == ClusterStatus.Ready
orderby item.Value.CreatedOn descending
select new ClusterView(
item.Key,
item.Value.AppCount,
item.Value.ServiceCount,
item.Value.Users.Count(),
this.config.MaximumUsersPerCluster,
this.config.MaximumClusterUptime - (DateTimeOffset.UtcNow - item.Value.CreatedOn.ToUniversalTime()));
}
答案 1 :(得分:2)
我不知道它是否是最好的"方式,但我一直在使用以下
public static async Task<IList<KeyValuePair<Guid, T>>> QueryReliableDictionary<T>(IReliableStateManager stateManager, string collectionName, Func<T, bool> filter)
{
var result = new List<KeyValuePair<Guid, T>>();
IReliableDictionary<Guid, T> reliableDictionary =
await stateManager.GetOrAddAsync<IReliableDictionary<Guid, T>>(collectionName);
using (ITransaction tx = stateManager.CreateTransaction())
{
IAsyncEnumerable<KeyValuePair<Guid, T>> asyncEnumerable = await reliableDictionary.CreateEnumerableAsync(tx);
using (IAsyncEnumerator<KeyValuePair<Guid, T>> asyncEnumerator = asyncEnumerable.GetAsyncEnumerator())
{
while (await asyncEnumerator.MoveNextAsync(CancellationToken.None))
{
if (filter(asyncEnumerator.Current.Value))
result.Add(asyncEnumerator.Current);
}
}
}
return result;
}
您可以通过传递StateManager,要查询的集合的名称以及带有查询逻辑的lambda函数来使用该方法。例如:
var queryResult = await QueryReliableDictionary<string>(this.StateManager, "CustomerCollection", name => !string.IsNullOrWhiteSpace(name) && (name.IndexOf("fred", StringComparison.OrdinalIgnoreCase) >= 0));
答案 2 :(得分:2)
在编写此答案时,IAsyncEnumerable
是dotnet库的一部分,C#8.0添加了语法糖来支持它。
问题在于ServiceFabric使用了自己的IAsyncEnumerable
定义,因此您不能对其应用dotnet扩展方法和C#助手。
我想出的一种解决方案是使用一个简单的包装程序将ServiceFabric的IAsyncEnumerable
转换为本地的:
using System.Threading;
using System.Threading.Tasks;
using Generic = System.Collections.Generic;
using Fabric = Microsoft.ServiceFabric.Data;
public static class FabricAsyncEnumerableExtensions
{
/// <summary>
/// Converts ServiceFabric <see cref="Microsoft.ServiceFabric.Data.IAsyncEnumerable"/> to dotnet native <see cref="System.Collections.Generic.IAsyncEnumerable"/>.
/// </summary>
public static Generic.IAsyncEnumerable<T> ToGeneric<T>(this Fabric.IAsyncEnumerable<T> source) =>
new AsyncEnumerableWrapper<T>(source);
private class AsyncEnumerableWrapper<T> : Generic.IAsyncEnumerable<T>
{
private readonly Fabric.IAsyncEnumerable<T> _source;
public AsyncEnumerableWrapper(Fabric.IAsyncEnumerable<T> source) => _source = source;
public Generic.IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken _ = default)
{
Fabric.IAsyncEnumerator<T> enumerator = _source.GetAsyncEnumerator();
return new AsyncEnumeratorWrapper<T>(enumerator);
}
}
private class AsyncEnumeratorWrapper<T> : Generic.IAsyncEnumerator<T>
{
private readonly Fabric.IAsyncEnumerator<T> _source;
public AsyncEnumeratorWrapper(Fabric.IAsyncEnumerator<T> source) => _source = source;
public async ValueTask DisposeAsync() =>
await Task.Run(_source.Dispose).ConfigureAwait(false);
public async ValueTask<bool> MoveNextAsync() =>
await _source.MoveNextAsync(default).ConfigureAwait(false);
public T Current => _source.Current;
}
}
使用它就像调用扩展方法一样简单,然后将其用作常规IAsyncEnumerable
:
Fabric.IAsyncEnumerable<KeyValuePair<Guid, Product>> asyncProducts = GetAsyncProducts();
return await asyncProducts.ToGeneric()
.Select(p => p.Value)
.ToListAsync()
.ConfigureAwait(false);
答案 3 :(得分:0)
据我所知,服务结构可靠的字典可能看起来像常规的.NET字典,但它们并不完全相同。因此,SF可靠字典或队列中可能不支持某些方法。