我已經實現了一個基本的(天真?)LINQ提供程序,可以用於我的目的,但我想解決一些怪癖,但我不知道如何。例如:如何使LINQ到對象處理投影?
// performing projection with Linq-to-Objects, since Linq-to-Sage won't handle this:
var vendorCodes = context.Vendors.ToList().Select(e => e.Key);
我IQueryProvider
實現了CreateQuery<TResult>
實現看起來像這樣:
public IQueryable<TResult> CreateQuery<TResult>(Expression expression)
{
return (IQueryable<TResult>)Activator
.CreateInstance(typeof(ViewSet<>)
.MakeGenericType(elementType), _view, this, expression, _context);
}
顯然這扼流圈當Expression
是MethodCallExpression
和TResult
是string
,所以我想我會執行該死的東西:
public IQueryable<TResult> CreateQuery<TResult>(Expression expression)
{
var elementType = TypeSystem.GetElementType(expression.Type);
if (elementType == typeof(EntityBase))
{
Debug.Assert(elementType == typeof(TResult));
return (IQueryable<TResult>)Activator.CreateInstance(typeof(ViewSet<>).MakeGenericType(elementType), _view, this, expression, _context);
}
var methodCallExpression = expression as MethodCallExpression;
if(methodCallExpression != null && methodCallExpression.Method.Name == "Select")
{
return (IQueryable<TResult>)Execute(methodCallExpression);
}
throw new NotSupportedException(string.Format("Expression '{0}' is not supported by this provider.", expression));
}
因此,當我運行我最終在我的private static object Execute<T>(Expression,ViewSet<T>)
重載,它打開最內層過濾器表達式的方法名稱,並在底層API中進行實際調用。
現在,在這種情況下,我經過Select
方法調用的表達,所以過濾器表達式爲null
和我switch
塊被忽略 - 這是很好的 - 在我被困在這裏:
var method = expression as MethodCallExpression;
if (method != null && method.Method.Name == "Select")
{
// handle projections
var returnType = method.Type.GenericTypeArguments[0];
var expType = typeof (Func<,>).MakeGenericType(typeof (T), returnType);
var body = method.Arguments[1] as Expression<Func<T,object>>;
if (body != null)
{
// body is null here because it should be as Expression<Func<T,expType>>
var compiled = body.Compile();
return viewSet.Select(string.Empty).AsEnumerable().Select(compiled);
}
}
爲了能夠將它傳遞給LINQ-to-Objects的Select
方法,我需要對我的MethodCallExpression
做些什麼?我是否正確地接近這個?
您可以從傳入Select方法獲得表達式,然後將其傳遞給ViewSet Select,或者將其編譯爲Func並將其傳遞到那裏。所以你只需重新投影到你的viewSet。 –
@SergeyLitvinov好的......那麼我該如何從'MethodCallExpression'中得到'Expression>? –
另外,如果我沒有'Func'返回類型的句柄,我怎樣才能將它轉換成正確的'Expression',以便能夠訪問'Compile'方法並保持強類型這樣'.Select(convertedExpression)'可以工作嗎? –