How can I use Linq on an ITypedList?

c# dynamic-linq linq

Question

So far, I find Linq can be used on existing fields and properties of a class, not on virtual properties. In other words, ITypedList can not work with Linq, even by dynamic Linq.

I tried the following code:

    IQueryable contact ; ...

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

Then, I met the exception of "No linkedPropertyName or field 'Customer' exists in type 'Contact'".

I traced into dynamic Linq and found the following code raised the exception:

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

in the method of Expression ParseMemberAccess(Type type, Expression instance).

It is obvious only real member of fields and properties are supported in Linq.

But I still expect someone may have found a way to do Linq on virtual properties.

If you find a way to do so, please share your experience.

Thank you in advance,

Ying

1
4
8/5/2010 6:27:49 PM

Popular Answer

This code isn't much better than code you'd write without linq expressions but here it goes.

This code assumes that your ITypedList is also an IList. Gets a property descriptor for the desired property and tests each item in the collection by doing what amounts to a 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);
3
2/24/2011 4:18:44 PM


Related Questions





Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow