使自定义类IQueryable [英] Making a custom class IQueryable

查看:59
本文介绍了使自定义类IQueryable的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have been working with the TFS API for VS2010 and had to query FieldCollection which I found isn't supported by LINQ so I wanted to create a custom class to make the Field and FieldCollection queryable by LINQ so I found a basic template and tried to implement it

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方法中遇到错误,因为它以字符串形式而不是字段形式传递

It appeared to compile and was recognized by LINQ but i keep getting an error in the CreateQuery method because it passes in string and not a field

    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类,请参见上面.

here is the Linq query I use... columnFilterList is List and fields is my custom FieldCollection class see above.

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

....我确定这是一个简单的错误...有人可以告诉我我在做什么错...谢谢

....I sure it is a simple mistake...could someone tell me what I am doing wrong...thanks

推荐答案

如果您希望LINQ使用某个对象,请实现IEnumerable<T>. IQueryable<T>对于LINQ to Objects来说是多余的.它旨在将表达式转换为另一种形式.

If you want an object to be usable by LINQ, implement IEnumerable<T>. IQueryable<T> is overkill for LINQ to Objects. It is designed for converting the expressions into another form.

或者,如果需要,您可以这样做

Or if you want, you can do this

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

这篇关于使自定义类IQueryable的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆