如何在ITypedList上做Linq?

时间:2010-08-05 05:51:14

标签: c# linq dynamic-linq

到目前为止,我发现Linq可以用于类的现有字段和属性,而不是虚拟属性。换句话说,ITypedList无法与Linq一起使用,即使是动态Linq。

我尝试了以下代码:

    IQueryable contact ; ...

    dynamic l = contact.Select("Customer.Name as Name"); 
   // Customer is a virtual property provided by the interface of ITypedList.

然后,我遇到了“联系人”类型中存在“没有linkedPropertyName或字段'客户'的例外情况。”

我追溯到动态Linq并发现以下代码引发了异常:

            MemberInfo member = FindPropertyOrField(type, id, instance == null);
            if (member == null)
                throw ParseError(errorPos, Res.UnknownPropertyOrField,
                    id, GetTypeName(type));
            return member is PropertyInfo ?
                Expression.Property(instance, (PropertyInfo)member) :
                Expression.Field(instance, (FieldInfo)member);

在Expression ParseMemberAccess(Type type,Expression instance)的方法中。

很明显,Linq只支持字段和属性的真实成员。

但我仍然希望有人可能找到了在虚拟财产上做Linq的方法。

如果您有办法,请分享您的经验。

提前谢谢你,

1 个答案:

答案 0 :(得分:2)

这段代码并没有比你没有linq表达式编写的代码好多了,但现在就去了。

此代码假定您的ITypedList也是IList。获取所需属性的属性描述符,并通过执行相当于for(int i = 0; i<((ICollection)list).Count; i ++)来测试集合中的每个项目 { ... }

        ParameterExpression listParameter = Expression.Parameter(
            typeof(ITypedList),
            "list"
        );
        ParameterExpression propertyDescriptorVariable = Expression.Variable(
            typeof(PropertyDescriptor),
            "propertyDescriptor"
        );
        ParameterExpression indexVariable = Expression.Variable(
            typeof(int),
            "index"
        );
        ParameterExpression resultVariable = Expression.Variable(
            typeof(bool),
            "result"
        );
        LabelTarget @break = Expression.Label();
        Expression<Func<ITypedList, bool>> lambdaExpression = Expression.Lambda<Func<ITypedList, bool>>(
            Expression.Block(
                new[] { propertyDescriptorVariable, indexVariable, resultVariable },
                Expression.Assign(
                    propertyDescriptorVariable,
                    Expression.Property(
                        Expression.Call(
                            listParameter,
                            typeof(ITypedList).GetMethod(
                                "GetItemProperties",
                                BindingFlags.Instance | BindingFlags.Public
                            ),
                            Expression.Default(
                                typeof(PropertyDescriptor[])
                            )
                        ),
                        typeof(PropertyDescriptorCollection).GetProperty(
                            "Item",
                            typeof(PropertyDescriptor),
                            new[] { typeof(string) }
                        ),
                        Expression.Constant(
                            "Name"
                        )
                    )
                ),
                Expression.Assign(
                    indexVariable,
                    Expression.Constant(
                        0,
                        typeof(int)
                    )
                ),
                Expression.Assign(
                    resultVariable,
                    Expression.Constant(
                        true
                    )
                ),
                Expression.Loop(
                    Expression.IfThenElse(
                        Expression.LessThan(
                            indexVariable,
                            Expression.Property(
                                Expression.Convert(
                                    listParameter,
                                    typeof(ICollection)
                                ),
                                "Count"
                            )
                        ),
                        Expression.IfThenElse(
                            Expression.Equal(
                                Expression.Constant(
                                    null
                                ),
                                Expression.Call(
                                    propertyDescriptorVariable,
                                    "GetValue",
                                    Type.EmptyTypes,
                                    Expression.Property(
                                        Expression.Convert(
                                            listParameter,
                                            typeof(IList)
                                        ),
                                        "Item",
                                        indexVariable
                                    )
                                )
                            ),
                            Expression.Block(
                                Expression.Assign(
                                    resultVariable,
                                    Expression.Constant(
                                        false
                                    )
                                ),
                                Expression.Break(
                                    @break
                                )
                            ),
                            Expression.PostIncrementAssign(
                                indexVariable
                            )
                        ),
                        Expression.Break(
                            @break
                        )
                    ),
                    @break
                ),
                resultVariable
            ),
            listParameter
        );
        bool isEveryNameNotNull = lambdaExpression.Compile().Invoke(list);