Воспользуйтесь преимуществами PLINQ с помощью пользовательских перечислимых расширений
Многие пользовательские расширения Enumerable могут быть реализованы в терминах других встроенных операций - например, этот простой метод удобства:
public static bool AnyOf<TElement>(this TElement item, IEnumerable<TElement> items)
{
return items.Any(a => EqualityComparer<TElement>.Default.Equals(a, item));
}
Теперь это заставит любой запрос PLINQ вернуться к последовательной операции, даже если PLINQ также имеет Any - и это эквивалентно просто изменению подписи:
public static bool AnyOf<T>(this T item, ParallelQuery<T> items)
{
return items.Any(a => EqualityComparer<T>.Default.Equals(a, item));
}
Но дублирование этого мне кажется грязным.
Сначала я подумал, что что-то вроде ниже может работать, но, конечно, это не так, потому что методы расширения являются статическими методами и, следовательно, решение о вызове Enumerable.Any
в отличие от ParallelQuery.Any
сделано во время компиляции на основе подписи.
public static bool AnyOf<TElement, TEnumerable>(this TElement item, TEnumerable items)
where TEnumerable : class, IEnumerable<TElement>
{
return items.Any(a => EqualityComparer<TElement>.Default.Equals(a, item));
}
Я пришел к выводу, что невозможно создать копию каждого метода с другой сигнатурой, но, возможно, я кое-что пропустил. (Ну и дела всегда с невозможными вопросами!)
Возможно, лучший пример помощника, который выиграет от распараллеливания (очевидно, может быть связан и т. Д.), Примерно так.
public static IEnumerable<string> ToStrings(this IEnumerable<object> ienum)
{
return ienum.Select(a=> a.ToString());
}
^ Ошибка компилятора:
The type 'ParallelQuery<TElement>' cannot be used as type parameter
'TEnumerable' in the generic type or method
'AnyOf<TElement,TEnumerable>(TElement, TEnumerable)'. There is no
implicit reference conversion from 'ParallelQuery<TElement>' to
'IEnumerable<TElement>'
Также стоит учесть, что не все методы ParallelQuery/Enumerable являются эквивалентными, даже если они компилируются.
2 ответа
Я сделал подобное для написания расширений IQueryable/IEnumerable. Попытка выделить общие биты включала объявление статической переменной, содержащей выражение, а затем ссылку на это выражение из двух разных версий функции. У меня больше нет кода, и когда я закончил, он был очень уродливым, и я не был доволен им. Вот тривиальный пример.
Expression<Func<PersonHistory, bool>> IsCurrent = (p) => p.Ends > DateTime.Now && p.Starts <= DateTime.Now;
//Then in each Extension method:
var query = db.PersonHistories.Where(IsCurrent);
В конечном счете, уровень дедупликации был совсем не хорошим, и его усложнили бы общие параметры. Может быть, это даст вам идею, хотя.
Ждем встречи с другими идеями.
Вы можете сделать это, используя проверенное приведение внутри метода (т.е. переключение во время выполнения) следующим образом:
public static bool AnyOf<TElement>(this TElement item, IEnumerable<TElement> items)
{
var parallelItems = items as ParallelQuery<TElement>
if(parallelItems != null)
{
return parallelItems.Any(a => EqualityComparer<TElement>.Default.Equals(a, item))
}
//other runtime checks
....
//else return default IEnumerable implementation
return items.Any(a => EqualityComparer<TElement>.Default.Equals(a, item));
}