VB Linq在动态对象上使用动态表达式排序

时间:2017-04-04 21:36:14

标签: vb.net linq dynamic lambda vb.net-2010

我有一个派生自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中工作将不胜感激。

1 个答案:

答案 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