Воспользуйтесь преимуществами 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));
}
Другие вопросы по тегам