[英]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);
在查询表达式中使用类型作为源的所有工作,就是编译上面的代码。 这意味着您将需要Cast
, Where
, Select
(以及其他类,例如GroupBy
, OrderBy
)方法作为实例方法或扩展方法。
例如,以下类和扩展方法将使上面的查询表达式编译(尽管这些方法根本不执行任何操作):
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.