我有一个派生自DynamicObject的类。我想使用属性(作为TypeDescriptor传递给BindingList ApplyCoreSort)进行排序。我从这里和其他网站尝试了很多例子,但是很多都是在C#中,并且不能很好地转换为VB。我发现这个MSDN blog的方法很简单,但在转换为VB时失败了:
Private Shared Function Sort(source As IEnumerable, [property] As String) As DynamicEntity()
Dim binder__1 = RuntimeBinder.Binder.GetMember(CSharpBinderFlags.None, [property], GetType(Example3), New CSharpArgumentInfo() {CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, Nothing)})
Dim param = Expression.Parameter(GetType(DynamicEntity), "o")
Dim getter = Expression.Dynamic(binder__1, GetType(Object), param)
Dim lambda = Expression.Lambda(Of Func(Of DynamicEntity, Object))(getter, param).Compile()
Return source.Cast(Of DynamicEntity)().OrderBy(lambda).ToArray()
End Function
主要是因为原始代码依赖于VB中的对象类型无法替代的动态类型:
Func(Of DynamicEntity, Object)
VS
Func<DynamicObject, dynamic>
C#等价物如下:
private IEnumerable<DynamicObject> SortAscending(IEnumerable<DynamicObject> source, PropertyDescriptor property, ListSortDirection direction)
{
CallSiteBinder binder__1 = RuntimeBinder.Binder.GetMember(CSharpBinderFlags.None, property.Name, property.PropertyType, new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) });
ParameterExpression param = Expression.Parameter(typeof(DynamicObject), "o");
DynamicExpression getter = Expression.Dynamic(binder__1, property.PropertyType, param);
dynamic lambda = Expression.Lambda<Func<DynamicObject, dynamic>>(getter, param).Compile();
if (direction == ListSortDirection.Ascending) {
return source.Cast<DynamicObject>().OrderBy(lambda).ToList;
} else {
return source.Cast<DynamicObject>().OrderByDescending(lambda).ToList;
}
}
不幸的是,将其转换回C#并将其放入另一个DLL不起作用,因为编译器抱怨IEnumerable类型不支持OrderBy或OrderByDescending。
任何人都可以建议一种方法来使这个工作在VB或建议一个实际工作的替代例子。将动态更改为对象不起作用,因为动态表达式编译器拒绝在运行时编译表达式,因为返回的是字符串而不是对象。
我已经检查了一些示例,但在尝试对动态对象进行排序时,它们似乎都没有正常工作,并且其中许多都不能使用.Net Framework 4在VS 2010 VB中编译。甚至是一种获取方法上述排序函数在VB中工作将不胜感激。
答案 0 :(得分:0)
您可以使用通用表达式树来调用linq的OrderBy(如答案here中所述)?
为方便起见,我在这里提供了该答案的VB版本(虽然不作为扩展名):
Public Shared Function Sort(Of T)(source As IQueryable(Of T), propertyName As String, sortOrder As ListSortDirection) As IQueryable(Of T)
Dim type = GetType(T)
Dim propertyInfo As PropertyInfo = type.GetProperty(propertyName)
Dim parameterExpression As ParameterExpression = Expression.Parameter(type, "p")
Dim propertyAccess As MemberExpression = Expression.MakeMemberAccess(parameterExpression, propertyInfo)
Dim sortExpression As LambdaExpression = Expression.Lambda(propertyAccess, parameterExpression)
Dim sortMethod = If(sortOrder = ListSortDirection.Ascending, "OrderBy", "OrderByDescending")
Dim resultExpression = Expression.[Call](
GetType(Queryable),
sortMethod,
New Type() {type, propertyInfo.PropertyType},
source.Expression,
Expression.Quote(sortExpression)
)
Return source.Provider.CreateQuery(Of T)(resultExpression)
End Function