У меня есть класс репозитория, который содержит потенциально большое количество элементов в памяти. Я хочу иметь возможность запрашивать его, используя LINQ-to-objects; подвох в том, что репозиторий должен быть потокобезопасным - ему необходимо заблокировать внутреннюю коллекцию на время запроса. Лучший синтаксис, который мне удалось придумать, продемонстрирован в примере кода ниже.
class Program
{
class Repository<T>
{
private List<T> _items;
public Repository(IEnumerable<T> items)
{
_items = items.ToList();
}
public List<TResult> Query<TResult>(Func<IEnumerable<T>, IEnumerable<TResult>> queryBuilder)
{
lock (_items)
{
var query = queryBuilder(_items);
return query.ToList();
}
}
}
static void Main(string[] args)
{
var repo = new Repository<int>(new[] { 1, 2, 4, 8, 16, 32 });
var result = repo.Query(r =>
from i in r
where i > 4
orderby i descending
select i.ToString());
foreach (var i in result)
Console.WriteLine(i);
Console.Read();
}
}
Приведенный выше код работает и гарантирует, что блокировка удерживается только столько времени, сколько требуется для выполнения запроса. Однако в идеале я хотел бы использовать более естественную парадигму LINQ и предоставить свойство типа IEnumerable {T} или IQueryable {T} из класса Repository, например, так:
static void Main(string[] args)
{
var repo = new Repository<int>(new[] { 1, 2, 4, 8, 16, 32 });
var result = from i in repo.Items
where i > 4
orderby i descending
select i);
foreach (var i in result)
Console.WriteLine(i);
Console.Read();
}
Я не могу понять, как это сделать, сохранив семантику блокировки исходного кода. Возможно ли это?