我很理解实现Linq的方法,但我在这里遇到的一个小问题是,我正在实现一个Linq到树的对象,树本身就是一个简单的树实现,所以我从创建可查询对象开始
public class TreeContext<T> : IOrderedQueryable where T :IComparable<T>
{
private Tree<T> _root;
private Expression _expression;
private IQueryProvider _provider;
public TreeContext(Tree<T> root)
{
_root = root;
Provider = new TreeProvider<T>(_root);
}
public TreeContext(IQueryProvider provider, Expression expression)
{
Provider = provider;
Expression = expression;
}
#region Model
public IEnumerable<TResult> Select<TResult>(Func<T,TResult> predicate)
{
var param = predicate.Method.GetParameters()[0];
return null;
}
public IEnumerable<T> Where(Func<T, bool> predicate)
{
Provider.Execute<IEnumerable>(Expression);
return null;
}
#endregion
public Expression Expression
{
private set { _expression = value; }
get { return _expression; }
}
public Type ElementType => typeof(T);
public IQueryProvider Provider
{
private set { _provider = value; }
get { return _provider; }
}
public IEnumerator<T> GetEnumerator()
=> GetEnumerator();
IEnumerator IEnumerable.GetEnumerator()
=>Provider.Execute<IEnumerable>(Expression).GetEnumerator();
}
然后我实现了QueryProvider,这里存在的问题,正是在选择方法实现上
public class TreeProvider<T> : IQueryProvider where T:IComparable<T>
{
private Tree<T> _root;
public TreeProvider(Tree<T> root)
=> _root = root;
public IQueryable CreateQuery(Expression expression)
=> new TreeContext<T>(this, expression);
public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
=>throw new NotImplementedException();
public object Execute(Expression expression)
=> new TreeQueryContext<T>(_root).Execute(expression);
public TResult Execute<TResult>(Expression expression)
{
throw new NotImplementedException();
}
}
没有为此自定义提供程序提供select实现,因此我可以编写如下请求从上下文中的el选择el
我添加了一个方法选择
IEnumerable Select<T、 TResult>(函数<T,TResult>选择器(
问题是,我没有找到一种方法将这个选择器转换为表达式,以便将其传递给QueryProvider的执行方法
也许我不太了解如何开发一个自定义LINQ到自定义提供商,我在C#中也没有找到任何关于这方面的好的完整教程
如果您想创建LINQ Provider,您必须始终使用表达式树来创建和解析查询。
TreeContext
中的Select
和Where
根本不需要。标准LINQ扩展具有这些方法,并将自动为您准备表达式树。重点关注TreeProvider
的实施。
由于您是该领域的新手,我建议您将LINQ提供程序建立在Relink上。它将从一开始就简化你的生活,并展示可能的实施方式。它有用于Provider和Query实现的基类,但不需要从它们派生。
试试
var queryParser = new QueryParser(new ExpressionTreeParser(
ExpressionTreeParser.CreateDefaultNodeTypeProvider(),
ExpressionTreeParser.CreateDefaultProcessor(
ExpressionTransformerRegistry.CreateDefault(),
null)));
var queryModel = parser.GetParsedQuery(expression);
Relink将为您提供QueryModel
,它更容易解析。