使自定义类IQueryable

我一直在使用VS2010的TFS API,并且不得不查询我发现LINQ不支持的FieldCollection,所以我想创建一个自定义类,使LINQ可以查询Field和FieldCollection,所以我找到了一个基本模板,并试图实现它

using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using Microsoft.TeamFoundation.WorkItemTracking.Client; public class WorkItemFieldCollection : IQueryable, IQueryProvider { private List _fieldList = new List(); #region Constructors ///  /// This constructor is called by the client to create the data source. ///  public WorkItemFieldCollection(FieldCollection fieldCollection) { foreach (Field field in fieldCollection) { _fieldList.Add(field); } } #endregion Constructors #region IQueryable Members Type IQueryable.ElementType { get { return typeof(Field); } } System.Linq.Expressions.Expression IQueryable.Expression { get { return Expression.Constant(this); } } IQueryProvider IQueryable.Provider { get { return this; } } #endregion IQueryable Members #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return (this as IQueryable).Provider.Execute<IEnumerator>(_expression); } private IList _field = new List(); private Expression _expression = null; #endregion IEnumerable Members #region IEnumerable Members System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return (IEnumerator)(this as IQueryable).GetEnumerator(); } private void ProcessExpression(Expression expression) { if (expression.NodeType == ExpressionType.Equal) { ProcessEqualResult((BinaryExpression)expression); } if (expression is UnaryExpression) { UnaryExpression uExp = expression as UnaryExpression; ProcessExpression(uExp.Operand); } else if (expression is LambdaExpression) { ProcessExpression(((LambdaExpression)expression).Body); } else if (expression is ParameterExpression) { if (((ParameterExpression)expression).Type == typeof(Field)) { _field = GetFields(); } } } private void ProcessEqualResult(BinaryExpression expression) { if (expression.Right.NodeType == ExpressionType.Constant) { string name = (String)((ConstantExpression)expression.Right).Value; ProceesItem(name); } } private void ProceesItem(string name) { IList filtered = new List(); foreach (Field field in GetFields()) { if (string.Compare(field.Name, name, true) == 0) { filtered.Add(field); } } _field = filtered; } private object GetValue(BinaryExpression expression) { if (expression.Right.NodeType == ExpressionType.Constant) { return ((ConstantExpression)expression.Right).Value; } return null; } private IList GetFields() { return _fieldList; } #endregion IEnumerable Members #region IQueryProvider Members IQueryable IQueryProvider.CreateQuery(System.Linq.Expressions.Expression expression) { if (typeof(S) != typeof(Field)) throw new Exception("Only " + typeof(Field).FullName + " objects are supported."); this._expression = expression; return (IQueryable)this; } IQueryable IQueryProvider.CreateQuery(System.Linq.Expressions.Expression expression) { return (IQueryable)(this as IQueryProvider).CreateQuery(expression); } TResult IQueryProvider.Execute(System.Linq.Expressions.Expression expression) { MethodCallExpression methodcall = _expression as MethodCallExpression; foreach (var param in methodcall.Arguments) { ProcessExpression(param); } return (TResult)_field.GetEnumerator(); } object IQueryProvider.Execute(System.Linq.Expressions.Expression expression) { return (this as IQueryProvider).Execute<IEnumerator>(expression); } #endregion IQueryProvider Members } 

它似乎编译并被LINQ识别但我在CreateQuery方法中不断收到错误,因为它传递的是字符串而不是字段

  IQueryable IQueryProvider.CreateQuery(System.Linq.Expressions.Expression expression) { if (typeof(S) != typeof(Field)) throw new Exception("Only " + typeof(Field).FullName + " objects are supported."); this._expression = expression; return (IQueryable)this; } 

这里是我使用的Linq查询… columnFilterList是List和fields是我的自定义FieldCollection类,见上文。

  foreach (var name in columnFilterList) { var fieldName = (from x in fields where x.Name == name select x.Name).First } 

….我确定这是一个简单的错误……有人能告诉我我做错了什么……谢谢

如果希望LINQ可以使用对象,请实现IEnumerable 。 对于LINQ to Objects, IQueryable是过度的。 它旨在将表达式转换为另一种forms。

或者如果你愿意,你可以这样做

 FieldCollection someFieldCollection = ... IEnumerable fields = someFieldCollections.Cast(); 

在您围绕现有IEnumerable Collection类型(即List包装和构建类的情况下,

你可能只使用一组暴露IQueryable接口的“前向函数”包装器:

 public class WorkItemFieldCollection : IEnumerable, IQueryable { ... #region Implementation of IQueryable public Type ElementType { get { return this._fieldList.AsQueryable().ElementType; } } public Expression Expression { get { return this._fieldList.AsQueryable().Expression; } } public IQueryProvider Provider { get { return this._fieldList.AsQueryable().Provider; } } #endregion ... } 

您现在可以直接查询WorkItemFieldCollection

 var workItemFieldCollection = new WorkItemFieldCollection(...); var Fuzz = "someStringId"; var workFieldItem = workItemFieldCollection.FirstOrDefault( c => c.Buzz == Fuzz );