2013-09-24 14 views
6

Ho lavorato con l'API TFS per VS2010 e ho dovuto interrogare FieldCollection che ho trovato non è supportato da LINQ, quindi volevo creare una classe personalizzata per rendere Field e FieldCollection interrogabili da LINQ in modo ho trovato un modello di base e ho cercato di attuarloCreazione di una classe personalizzata 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 
} 

sembrava di compilare ed è stato riconosciuto da LINQ, ma continuo a ricevere un errore nel metodo createQuery perché passa in stringa e non un campo

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

ecco la query di Linq che uso ... c olumnFilterList è List e fields è la mia classe FieldCollection personalizzata vedi sopra.

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

.... Sono sicuro che si tratta di un semplice errore ... qualcuno potrebbe dirmi che cosa sto facendo male ... grazie

risposta

3

Se si desidera un oggetto sia usabile da LINQ, implementano IEnumerable<T>. IQueryable<T> è eccessivo per LINQ su oggetti. È progettato per convertire le espressioni in un'altra forma.

Oppure, se si vuole, si può fare questo

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

Questo è esattamente ciò di cui avevo bisogno. Stavo cercando di superare il problema. Grazie! – user2810977

+0

e per ordinarli per nome: fields.OrderBy (f => f.Nome) –

0

Nel tuo caso di avvolgimento e la costruzione di una classe intorno a un tipo di raccolta IEnumerable esistente cioè List<Field>,

si potrebbe anche utilizzare un insieme di " funzione avanti" wrapper che espongono l'interfaccia 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 
    ... 
} 

È ora possibile interrogare direttamente la tua WorkItemFieldCollection:

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