How to do Linq on ITypedList?
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
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);
精彩评论