7

许多自定义 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 方法都是等效的,即使它们可以编译。

4

2 回答 2

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));
}
于 2012-12-19T14:54:19.037 回答
1

I have done similar for writing IQueryable/IEnumerable extensions. Trying to factor out the common bits involved declaring static variable holding an Expression, and then referencing that expression from the two different versions of the function. I don't have the code anymore, and when I was done, it was very ugly and I wasn't satisfied with it. Here is a trivial example.

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

Ultimately the level of de-duplication was not good at all, and would be made more complicated by generic parameters. Maybe this will give you an idea though.

Looking forward to seeing others ideas.

于 2012-12-19T02:53:51.480 回答