利用PLINQ和自定义Enumerable Extensions

时间:2012-12-19 01:56:42

标签: c# linq 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 个答案:

答案 0 :(得分:1)

我已经完成了类似的编写IQueryable / IEnumerable扩展。尝试分解公共位涉及声明保存Expression的静态变量,然后从函数的两个不同版本引用该表达式。我没有代码了,当我完成时,它非常难看,我对它不满意。这是一个简单的例子。

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);

最终,重复数据删除的程度根本不好,并且通用参数会使复杂程度变得更加复杂。也许这会给你一个想法。

期待看到别人的想法。

答案 1 :(得分:1)

您可以通过在方法中使用格式化转换(即运行时切换)来执行此操作,如下所示:

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));
}