根据属性的名称查找不同的元素
本文关键字:元素 查找 属性 | 更新日期: 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}