2013-09-24 16 views
6

Pracowałem z interfejsem TFS API dla VS2010 i musiałem wysyłać zapytania do FieldCollection, które znalazłem nie jest obsługiwane przez LINQ, więc chciałem utworzyć niestandardową klasę, która sprawi, że Field i FieldCollection będą przetwarzane przez LINQ, więc Znalazłem podstawowy szablon i starał się wdrożyć goTworzenie niestandardowej klasy 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 
} 

Wydawało się skompilować i został uznany przez LINQ ale wciąż otrzymuję błąd w metodzie CreateQuery ponieważ przechodzi w ciąg, a nie pole

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

Oto kwerenda Linq używam ... c olumnFilterList to lista, a pola to moja niestandardowa klasa FieldCollection, patrz wyżej.

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

.... I na pewno jest to prosty błąd ... może ktoś mi powiedzieć co robię źle ... dzięki

Odpowiedz

3

Jeśli chcesz być przedmiotem do użytku przez LINQ, wdrożenia IEnumerable<T>. IQueryable<T> jest przesadą dla LINQ do obiektów. Przeznaczony jest do przekształcania wyrażeń w inną formę.

Lub jeśli chcesz, możesz to zrobić

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

Dokładnie tego potrzebowałem. Próbowałem przemyśleć problem. Dziękuję Ci! – user2810977

+0

i posortuj je według nazwy: fields.OrderBy (f => f.Name) –

0

W twoim przypadku pakowania i budowania klasę wokół istniejącego IEnumerable typu Collection tj List<Field>,

może po prostu użyć zestawu " funkcja naprzód”owijarki, które narażają interfejsu 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 
    ... 
} 

teraz można bezpośrednio zapytanie do WorkItemFieldCollection:

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