繁体   English   中英

使不从IEnumerable <>继承的对象可通过LINQ查询

[英]Making Objects that Don't Inherit from IEnumerable<> Queryable via LINQ

我有一个名为类IDCollection这实际上不是一个List<> Dictionary<,> ,或类似IEnumerable基类型。 尽管它确实有一个索引器 ,但是它基于一个称为innerList的私有Dictionary<string, ID> ,因此该类的对象本身不是list ,也没有通过其自身的this访问器保存键值对或项目集合。

是否可以在LINQ表达式IDCollection对象可查询? 如果是这样,怎么办?

例如,假设该对象名为testIdColl 在这种情况下...

from KeyValuePair<string, ID> k in testIDColl
select k;

等等

IQueryable接口是否完全涉及?

这是您需要对您的班级做的所有事情:

public class IDCollection : IEnumerable<KeyValuePair<string, ID>>
{
    private IDictionary<string, ID> List = new Dictionary<string, ID>();

    public IEnumerator<KeyValuePair<string, ID>> GetEnumerator()
    {
        return List.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }
}

然后,您可以运行以下代码:

var testIDColl = new IDCollection();

var query =
    from KeyValuePair<string, ID> k in testIDColl
    select k;

如果需要,可以将整个IEnumerable<...>接口IEnumerable<...>私有,如下所示:

public class IDCollection : IEnumerable<KeyValuePair<string, ID>>
{
    private IDictionary<string, ID> List = new Dictionary<string, ID>();

    IEnumerator<KeyValuePair<string, ID>> IEnumerable<KeyValuePair<string, ID>>.GetEnumerator()
    {
        return List.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return List.GetEnumerator();
    }
}

现在什么都没有直接暴露出来。

我从Jakub的答案中创建了三个实例方法的实现:

public class IDCollection
{
    private IDictionary<string, ID> List = new Dictionary<string, ID>() { { "x", new ID() }, } ;

    public IEnumerable<KeyValuePair<string, ID>> Where(Func<KeyValuePair<string, ID>, bool> selector)
    {
        return List.Where(selector);
    }

    public IEnumerable<TResult> Select<TResult>(Func<KeyValuePair<string, ID>, TResult> selector)
    {
        return List.Select(selector);
    }
}

执行基本查询不需要Cast方法。

我建议添加一个显式的AsEnumerable()方法来公开LINQ运算符的全部范围。

这将是执行查询的最简单,最可靠的方法:

public class IDCollection
{
    private IDictionary<string, ID> List = new Dictionary<string, ID>() { { "x", new ID() }, } ;

    public IEnumerable<KeyValuePair<string, ID>> AsEnumerable()
    {
        return List.Select(x => x);
    }
}

查询必须看起来像:

var query =
    from k in testIDColl.AsEnumerable()
    where k.Key == "x"
    select k;

最简单的解决方案是实现IEnumerable<T> 这只是一种方法,通常可以将其委派给内部集合的GetEnumerator()或使用yield return轻松实现。

您的类型名称( IDCollection )建议它应该实现IEnumerable<T> ,可能是其他一些集合接口(例如ICollection<T>IReadonlyCollection<T> )。

如果由于某种原因您不想使用IEnumerable<T> ,您仍然可以使其工作。 首先,您需要了解编译器如何处理查询表达式。

LINQ查询表达式首先由编译器转换为一系列方法调用。 例如查询表达式

from KeyValuePair<string, int> item in collection
where item.Key == "abc"
select item.Value;

被翻译成

testIDColl
    .Cast<KeyValuePair<string, int>>()
    .Where(item => item.Key == "abc")
    .Select(item => item.Value);

在查询表达式中使用类型作为源的所有工作,就是编译上面的代码。 这意味着您将需要CastWhereSelect (以及其他类,例如GroupByOrderBy )方法作为实例方法或扩展方法。

例如,以下类和扩展方法将使上面的查询表达式编译(尽管这些方法根本不执行任何操作):

class IDCollection
{

}

static class IDCollectionExtensions
{
    public static IDCollection Cast<TResult>(this IDCollection source)
    {
        return source;
    }

    public static IDCollection Where(this IDCollection source, Func<KeyValuePair<string, int>, bool> selector)
    {
        return source;
    }

    public static IDCollection Select<TResult>(this IDCollection source, Func<KeyValuePair<string, int>, TResult> selector)
    {
        return source;
    }
}

实例方法也将起作用:

class IDCollection
{
    public IDCollection Cast<TResult>()
    {
        return this;
    }

    public IDCollection Where(Func<KeyValuePair<string, int>, bool> selector)
    {
        return this;
    }

    public IDCollection Select<TResult>(Func<KeyValuePair<string, int>, TResult> selector)
    {
        return this;
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM