根据属性的名称查找不同的元素

本文关键字:元素 查找 属性 | 更新日期: 2023-09-27 18:18:55

我正在尝试构建一个通用的过滤器控件,显示数据网格中的唯一值,并允许用户过滤网格中特定列的唯一值。

我喜欢这个问题的答案,但是所有这些都要求你事先知道属性。我想使代码OCP兼容,只有一个方法,采用属性名称字符串,并应用不同的功能(可能使用反射)。考虑到我的列(因此要过滤的列名,如Name、Age等是动态的),这个问题的最佳解决方案是什么?

特别地,我试图避免这个switch case语句:

switch (listColumn.DisplayMemberPath)
{
    case "Name" :
            listColumn.Items = GridItems.GroupBy(item => item.Name).Select(item => item.First());
            break;
    case "Age" :
            listColumn.Items = GridItems.GroupBy(item=> item.Age).Select(item => item.First());
            break;
    // and so on...
 }

并有一个像这样的泛型方法:

public IEnumerable GetDistinctValues(IEnumerable gridItems, string propertyName)
{
    // logic to return the distinct values for the given property name...
}

仅供参考-我在ViewModel中的集合类型为ICollectionView(猜测在CollectionView中已经定义了类似的东西,可以进行我正在寻找的过滤)。

根据属性的名称查找不同的元素

你可以像下面这样使用c#的表达式树特性。

public static IEnumerable GetDistinctValues<T>(IEnumerable<T> gridItems, string propertyName) where T : class
{
    // logic to return the distinct values for the given property name...
    var xpre = GetPropertyExpression<T>(typeof(T), propertyName);
    return gridItems.GroupBy(item => xpre).Select(item => item.First());
}
private static Func<T, object> GetPropertyExpression<T>(Type type, string propertyName)
{
    ParameterExpression parameter = Expression.Parameter(type, "x");
    MemberExpression propertyExpr = GetPropertyExpression(parameter, type, propertyName);
    if (propertyExpr == null)
        return null;
    Expression<Func<T, object>> expression = Expression.Lambda<Func<T, object>>(Expression.Convert(propertyExpr, typeof(object)), new ParameterExpression[1] { parameter });
    return expression.Compile();
}
private static MemberExpression GetPropertyExpression(Expression param, Type type, string propertyName)
{
    var property = type.GetProperty(propertyName);
    if (property == null)
    {
        if (propertyName.Contains("_") || propertyName.Contains("."))
        {
            var innerProps = propertyName.Split(new char[] { '_', '.' }, 2);
            property = type.GetProperty(innerProps[0]);
            if (property != null)
            {
                var pe = Expression.Property(param, property);
                return GetPropertyExpression(pe, property.PropertyType, innerProps[1]);
            }
            else
            {
                return null;
            }
        }
    }
    else
    {
        return Expression.Property(param, property);
    }
    return param as MemberExpression;
}

用法:

var lst = new List<Student>();
lst.Add(new Student { Name = "Joe", Age = 23 });
lst.Add(new Student { Name = "John", Age = 28 });
lst.Add(new Student { Name = "Jane", Age = 21 });
lst.Add(new Student { Name = "John", Age = 15 });
var vals = GetDistinctValues(lst, "Name"); // here

你可以这样做:

void GetDistinctValues(string aPropName)
{
    var props = typeof(A).GetProperties();
    // make sure your property exists here, otherwise return
    // Something like that should be what you want:
    var return_col = gridItems[aPropName].Distinct();
}
public class A {
    public int Age{get;set;}
    public int Height{get;set;}
}

基本上,确保列/属性存在,然后简单地在其上运行一个linq distinct。


关于你的注释,你传入一个IEnumerable,所以你可以调用Distinct:

var nmrbl = Enumerable.Range(1,10).Select (e => e%3);
// nmrbl={ 1 ,2 ,0 ,1 ,2 ,0 ,1 ,2 ,0 ,1}
var dist = nmrbl.Distinct();
// dist = {1,2,0}