我一直在使用VS2010的TFS API,并且不得不查询我发现LINQ不支持的FieldCollection,所以我想创建一个自定义类,使LINQ可以查询Field和FieldCollection所以我找到了一个基本的模板并试图实施它
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,字段是我的自定义FieldCollection类,见上文。
foreach (var name in columnFilterList)
{
var fieldName = (from x in fields where x.Name == name select x.Name).First
}
....我确定这是一个简单的错误......有人能告诉我我做错了什么......谢谢
答案 0 :(得分:4)
如果希望LINQ可以使用对象,请实现IEnumerable<T>
。 LINQ to Objects对IQueryable<T>
来说太过分了。它旨在将表达式转换为另一种形式。
或者,如果你愿意,你可以这样做
FieldCollection someFieldCollection = ...
IEnumerable<Field> fields = someFieldCollections.Cast<Field>();
答案 1 :(得分:0)
在围绕现有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 );