12

私はVS2010用のTFS APIを使用しており、LINQでサポートされていないことがわかったFieldCollectionをクエリする必要があったため、カスタムクラスを作成してFieldとFieldCollectionをLINQでクエリ可能にしたかったので、基本的なテンプレートを見つけて試しました実装する

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クエリです... columnFilterListはListで、fieldsは上記のカスタムFieldCollectionクラスです。

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

....単純な間違いだと思います...誰かが私が間違っていることを教えてくれませんか...ありがとう

4

2 に答える 2

5

オブジェクトを LINQ で使用できるようにする場合は、 を実装しIEnumerable<T>ます。IQueryable<T>LINQ to Objects ではやり過ぎです。式を別の形式に変換するために設計されています。

または、必要に応じて、これを行うことができます

FieldCollection someFieldCollection = ...
IEnumerable<Field> fields = someFieldCollections.Cast<Field>();
于 2013-09-24T12:52:38.910 に答える
1

既存の IEnumerable Collection タイプをラップしてクラスを構築する場合、つまり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 );
于 2016-09-02T10:35:20.967 に答える