2013-09-24 40 views
6

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

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Linq.Expressions; 
using Microsoft.TeamFoundation.WorkItemTracking.Client; 

public class WorkItemFieldCollection : IQueryable<Field>, IQueryProvider 
{ 
    private List<Field> _fieldList = new List<Field>(); 

    #region Constructors 

    /// <summary> 
    /// This constructor is called by the client to create the data source. 
    /// </summary> 
    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<Field> Members 

    IEnumerator<Field> IEnumerable<Field>.GetEnumerator() 
    { 
     return (this as IQueryable).Provider.Execute<IEnumerator<Field>>(_expression); 
    } 

    private IList<Field> _field = new List<Field>(); 
    private Expression _expression = null; 

    #endregion IEnumerable<Field> Members 

    #region IEnumerable Members 

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() 
    { 
     return (IEnumerator<Field>)(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<Field> filtered = new List<Field>(); 

     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<Field> GetFields() 
    { 
     return _fieldList; 
    } 

    #endregion IEnumerable Members 

    #region IQueryProvider Members 

    IQueryable<S> IQueryProvider.CreateQuery<S>(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<S>)this; 
    } 

    IQueryable IQueryProvider.CreateQuery(System.Linq.Expressions.Expression expression) 
    { 
     return (IQueryable<Field>)(this as IQueryProvider).CreateQuery<Field>(expression); 
    } 

    TResult IQueryProvider.Execute<TResult>(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<Field>>(expression); 
    } 

    #endregion IQueryProvider Members 
} 

看来编译并通过LINQ的认可,但我一直在的createQuery方法得到一个错误,因为它传递的字符串,而不是一个场

IQueryable<S> IQueryProvider.CreateQuery<S>(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<S>)this; 
    } 

这里是我使用的Linq查询... c olumnFilterList是列表和字段是我的自定义FieldCollection类见上文。

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

....我相信这是一个简单的错误...有人能告诉我什么,我做错了...感谢

回答

3

如果你希望对象是通过LINQ使用,实现IEnumerable<T>。对于LINQ to Objects而言,IQueryable<T>是矫枉过正的。它旨在将表达式转换为另一种形式。

或者,如果你愿意,你可以做到这一点

FieldCollection someFieldCollection = ... 
IEnumerable<Field> fields = someFieldCollections.Cast<Field>(); 
+0

这正是我所需要的。我试图过度考虑问题。谢谢! – user2810977

+0

并按名称排序: fields.OrderBy(f => f.Name) –

0

在你包装的情况下,建设围绕现有IEnumerable集合类型,即List<Field>类,

你可能只使用一组“转发功能”暴露出IQueryable<Field>接口封装:

public class WorkItemFieldCollection : IEnumerable<Field>, IQueryable<Field> 
{ 
    ... 
    #region Implementation of IQueryable<Field> 

    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);