我正在编写自定义IQueryable,以使用Web服务。 Web服务具有有限的查询功能。 所以我想要的是,查询我的IQueryable中的Web服务,然后从webservice上执行数据的给定表达式。
我的IQueryable实现如下:
public class CloudInfoQuery : IQueryable<CloudContentModel>
{
private string _accessToken;
public Type ElementType => typeof(CloudContentModel);
public Expression Expression
{
get;
private set;
}
public IQueryProvider Provider
{
get;
private set;
}
internal CloudInfoQuery(string accessToken)
{
_accessToken = accessToken;
Provider = new CloudInfoProvider(accessToken);
Expression = Expression.Constant(this);
}
internal CloudInfoQuery(string accessToken, IQueryProvider provider, Expression expression) : this(accessToken)
{
Provider = provider;
Expression = expression;
}
public IEnumerator<CloudContentModel> GetEnumerator()
{
return Provider.Execute<IEnumerable<CloudContentModel>>(Expression).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
Execute
中的IQueryProvider
如下所示:
public object Execute(Expression expression)
{
List<CloudContentModel> cloudContent = GetContentFromWebService(expression);
return cloudContents.AsQueryable().Provider.Execute(mExpression):
}
我正在从查询中分析可能的过滤器并将它们用于Web服务调用。 之后我想在结果上执行表达式,以便所有过滤器都适用,web服务不支持。
但是当我这样做的时候,由于Expression = Expression.Constant(this);
中的CloudInfoQuery
,会有无限循环。
我尝试删除Expression,这会导致表达式树出现无限循环,或者通过更新MethodCallExpression来更改它。
但后来我将面临System.ArgumentException: Static method requires null instance, non-static method requires non-null instance
。
以下,我尝试过并导致上述异常:
从树中删除表达式
MethodCallExpression mExpression = expression as MethodCallExpression;
mExpression = mExpression.Update(expression, mExpression.Arguments.Skip(1));
使用新表达式更新为
MethodCallExpression mExpression = expression as MethodCallExpression;
mExpression = mExpression.Update(Expression.Constant(cloudContents), mExpression.Arguments.Skip(1));
在表达式树的顶部设置一个新表达式
MethodCallExpression mExpression = expression as MethodCallExpression;
List<Expression> exs = new List<Expression>();
exs.Add(Expression.Constant(cloudContents));
exs.AddRange(mExpression.Arguments.Skip(1));
mExpression = mExpression.Update(expression, exs);
我也试图像这样阻止无限循环:
private IEnumerabe<CloudContentModel> _cloudContents;
public object Execute(Expression expression)
{
if(_cloudContents != null)
{
return _cloudContents;
}
List<CloudContentModel> cloudContent = GetContentFromWebService(expression);
_cloudContents = cloudContents.AsQueryable().Provider.Execute(mExpression);
return _cloudContents:
}
但是其他过滤器无效。 那么如何将表达式传递给另一个List?
答案 0 :(得分:2)
好的,多亏了相关部分,我找到了一个受此启发的解决方案:How do you transfer the execution of a Expression created by an IQueryable object to a IEnumerable?
public class CloudInfoQuery : IQueryable<CloudContentModel>
{
private string _accessToken;
private List<CloudContentModel> _cloudContents = new List<CloudContentModel>();
public Type ElementType => typeof(CloudContentModel);
public Expression Expression
{
get;
private set;
}
public IQueryProvider Provider
{
get;
private set;
}
internal CloudInfoQuery(string accessToken)
{
_accessToken = accessToken;
Provider = new CloudInfoProvider(accessToken, _cloudContents);
Expression = _cloudContents.AsQueryable().Expression;
}
internal CloudInfoQuery(string accessToken, IQueryProvider provider, Expression expression) : this(accessToken)
{
Provider = provider;
Expression = expression;
}
public IEnumerator<CloudContentModel> GetEnumerator()
{
return Provider.Execute<IEnumerable<CloudContentModel>>(Expression).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
public class CloudInfoProvider : IQueryProvider
{
private string _accessToken;
private List<CloudContentModel> _cloudContents = null;
public CloudInfoProvider(string accessToken, List<CloudContentModel> cloudContent)
{
_accessToken = accessToken;
_cloudContents = cloudContent;
}
public IQueryable CreateQuery(Expression expression)
{
return new CloudInfoQuery(_accessToken, this, expression);
}
public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
{
return (IQueryable<TElement>)new CloudInfoQuery(_accessToken, this, expression);
}
public object Execute(Expression expression)
{
_cloudContent.Clear();
_cloudContent.AddRange(GetContentFromWebService(expression));
return cloudContents.AsQueryable().Provider.CreateQuery(expression):
}
public TResult Execute<TResult>(Expression expression)
{
return (TResult)Execute(expression);
}
}
诀窍是,使用来自同一实例的表达式,稍后将包含要过滤的数据。
Expression = _cloudContents.AsQueryable().Expression;