在单个元素级别应用Linq Func <T,TResult>键选择器

Smu*_*202 10 c# generics .net-4.0 linq-to-sql

对不起,如果标题有误导性,不知道如何描述这个.

我的最终目标是要具有的扩展方法IQueryable<T>表达的和某种形式的(见下文的实施例),将允许我不得不返回IQueryable<EntityIndex<T>>(或类似的),其包含原始TEntity字段,和阵列/ IEnumerable的含有元素正如某种形式的表达所描述的那样.

我知道这没有多大意义,希望它会在一个例子之后......

这是我到目前为止:

class EntityIndex<T, TKey>
{
    T Entity { get; set; }
    // Doesn't have to be IEnumerable, whatever is easier
    IEnuermable<TKey> Index { get; set; }
}
static class Elsewhere
{
    [Extension()]
    public IQueryable<EntityIndex<T, TKey>> IndexBy<T, TKey>(this IQueryable<T> source, Expression<Func<T, TKey[]>> indexSelector)
    {
        return source.Select(n => new EntityIndex<T, TKey> {
            Entity = n,
            Index = new T[] { n }.Select(indexSelector)
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

注意:上面没有编译,它只是尝试显示我想要实现的目标.

我已经使用了标准选择器,但是次优,不得不随意创建一个T赋值给'Index'属性的数组,以便能够应用选择器.我希望更好的参数选择可以解决这个问题,但可能不会.主要的问题是这不会编译,所以如果有一个小的调整,将允许它工作,我很好,如果你能理解我的胡言乱语,了解我正在尝试做什么,并碰巧知道一个更好的方法为此,我将非常感激.

理想情况下,我需要L2S引擎理解解决方案,我不相信上面的内容是由于引入了EntityIndex类,但我希望它能将它视为一个匿名类.

编辑:

好点Damien,更大的图片可能更容易描述......

我想要一个接受表达式的扩展方法,该表达式应描述要索引的实体上的哪些字段,这些字段将在此特定表达式之后使用,以允许将标准(where子句)应用于所选字段.

长话短说,在代码中的很多地方我们都有一个通配符字符串搜索.如果我有一个带有Property1,Property2,Property3等的EntityA,那么看到以下代码并不罕见:

手写,请原谅小错字

public string[] WildcardSearch(string prefixText, int count)
{
    string searchTerm = prefixText.Replace(wildcard, string.Empty);
    if (prefixText.StartsWith(wildcard) && prefixText.EndsWith(wildcard)) {
        return entitySet.Where(n => n.Property1.Contains(searchTerm) || n.Property2.Contains(searchTerm)).Select(n => n.Property3).ToArray();
    } else if (prefixText.StartsWith(wildcard)) {
        return entitySet.Where(n => n.Property1.EndsWith(searchTerm) || n.Property2.EndsWith(searchTerm)).Select(n => n.Property3).ToArray();
        // you get the picture, same with EndsWith, no wildcards defaults to contains...
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:

进一步说明 - 以上面的WildcardEarch为例,我希望能够拥有如下选择:

Func<EntityA, IEnumerable<string>> indexSelector = n => new string[] {
    n.Property1,
    n.Property2
};

// Alternatively, a ParamArray of keySelector might work?
Func<EntityA, string>[] keySelectors = new Func<EntityA, string>[] {
    n => n.Property1,
    n => n.Property2
};
Run Code Online (Sandbox Code Playgroud)

给出足够的表达式来描述要搜索的实体上的哪些字段,IQueryable<EntitySearch<T>>如上所示返回,我希望能够应用单个标准,类似于:

Func<EntitySearch<T>, bool> criterion = n => false;
if (wildcardIsContains) {
    criterion = n => n.Values.Any(x => x.Contains(searchTerm));
} else if (wildCardIsStartsWith) {
    criterion = n => n.Values.Any(x => x.Contains(searchTerm));
    //etc
}
Run Code Online (Sandbox Code Playgroud)

鉴于我无法工作的最顶层的扩展,以及这个标准逻辑,我应该能够IQueryable<T>选择一些字段,并在字段上应用适当的通配符搜索,最后IQueryable<T>再次添加过滤.

Thanks¬!

如果您需要更多信息/说明,请发表评论......

编辑:公平的@subkamren并感谢您的兴趣.一些非通用示例可能有用.我会起草一些内容并很快添加它们.目前,根据您的评论进行一些澄清......

鉴于IQueryable<Animal>我想要一个扩展,允许我在Animal上选择我打算搜索/索引的字段.例如,Animal.Description, Animal.Species.Name等等.此扩展名应返回类似的内容IIndexedQueryable<Animal>.这是我在上面的问题中试图解决的问题.如果您愿意提供帮助,我提到的更广泛的情况如下:

IIndexedQueryable<T>反过来我想的扩展,这可能需要一个界面string搜索词.扩展名应解析搜索项中的通配符,使用必要的标准扩展原始IQueryable以对索引字段执行搜索,然后IQueryable<T>再次返回.

我很欣赏这可以在一个步骤中完成,但我希望这样做,以便稍后我可以考虑添加第三个扩展方法,IIndexedQueryable<T>允许我使用SQL Server执行自由文本搜索... ^^ Make任何意义?

这至少是一个更大的图景,这个问题主要涉及能够指定我打算以这样的方式索引的字段,我可以在此后使用它们.

Chr*_*ain 4

所以像这样:

public static IEnumerable<EntityIndex<T, Y>> IndexBy<T, Y>(this IEnumerable<T> entities, Func<T, Y> indexSelector) {
    return entities.Select(e => new EntityIndex<T, Y> { Entity = e, IndexValue = indexSelector(e) });
}
Run Code Online (Sandbox Code Playgroud)

请注意,使用 TIndexType(此处称为 Y)一般定义 EntityIndex 很重要,因为您事先不知道索引是什么。使用泛型允许 Y 成为枚举,因此以下内容将用作索引选择器:

// Assuming Animal has attributes "Kingdom", "Phylum", "Family", "Genus", "Species"
// this returns an enumeration of EntityIndex<Animal, String[]>
var animalsClassified = someAnimals.IndexBy(a => new String[] { a.Kingdom, a.Phylum, a.Family, a.Genus, a.Species });
Run Code Online (Sandbox Code Playgroud)

编辑(添加更多细节):

使用上面的内容,您可以按唯一索引值对结果进行分组:

var animalClassifications = animalsClassified
                                .SelectMany(ac => ac.IndexValue.Select(iv => new { IndexValue = iv, Entity = ac.Entity }))
                                .GroupBy(kvp => kvp.IndexValue)
Run Code Online (Sandbox Code Playgroud)

顺便说一句,我在这里描述的是 Google 推广的 MapReduce 算法(一种非常简化的形式)。其分布式形式通常用于文本搜索中的关键字识别,您希望在其中构建(搜索词)->(包含文档的列表)的索引。