制作不需要的对象;t从IEnumerable<>;可通过LINQ进行查询
本文关键字:可通过 gt lt LINQ 查询 IEnumerable 不需要 对象 | 更新日期: 2023-09-27 18:29:44
我有一个名为IDCollection
的类,它实际上是基于List<>
、Dictionary<,>
或类似IEnumerable
的类型,而不是。尽管它有一个索引器,但它基于一个名为innerList
的私有Dictionary<string, ID>
,因此类的对象本身不是列表。它也不通过自己的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<...>
接口私有化,比如:
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;
}
}