以学生类为例
public class Student
{
public string Name { get; set; }
public int Age { get; set; }
public string Gender { get; set; }
}
一、单条件
利用表达式Expression实现动态单条件分组(成功)
//用来作分组条件的字段
string groupCondition = "Gender";
//生成e的指向
var parameter = Expression.Parameter(typeof(Student), "e");
//根据groupCondition分组 生成e.Gender
var propertyReference = Expression.Property(parameter, groupCondition);
//生成Lambda表达式
var func = Expression.Lambda<Func<Student, object>>(propertyReference, new[] { parameter }).Compile();
//执行分组 where用来筛选出组内数据大于一条的组
var allUnique = students.GroupBy(func).Where(o => o.Count() > 1).Select(c => c.ToList());
二、多条件
1.直接使用三目运算符来判断哪些字段需要用于分组(成功)
//groupby会自动忽略空字符串""
var allUnique = students.GroupBy(e => new
{
Gender = 判断条件1 ? "" : e.Gender,
Name= 判断条件2 ? "" : e.Name,
Age = 判断条件3 ? "" : e.Age,
}).Where(o => o.Count() > 1).Select(c => c.ToList());
2.利用IGrouping接口实现分组(成功)
string conditionString = "Gender,Name,Age"
//用字符串数组存储分组条件
string[] conditionArray = conditionString.Split(new char[] { ',', ',' });
List<DGroupBy<T>> result= new List<DGroupBy<T>>();
var itemList = sendRequests.Select(u => new
{
key = keys.Select(p =>
{
var property = u.GetType().GetProperty(p);
if (property != null)
{
return property.GetValue(u, null);
}
else
{//未获取到属性
return "";
}
}).ToArray(),
value = u
});
//分组条件conditionArray,需要分组的数据students,分组结果list
foreach (var item in itemList)
{
DGroupBy<T> existing = result.SingleOrDefault(u => u.Key.Zip(item.key, (a, b) => a.Equals(b)).All(p => p));
if (existing == null)
{
existing = new DGroupBy<T>(item.key);
result.Add(existing);
}
existing.Add(item.value);
}
public class DGroupBy<T> : IGrouping<object[], T>
{
private List<T> _innerlist = new List<T>();
private object[] _key;
public DGroupBy(object[] key) { _key = key; }
public object[] Key
{
get { return _key; }
}
public void Add(T value)
{
_innerlist.Add(value);
}
public IEnumerator<T> GetEnumerator()
{
return this._innerlist.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this._innerlist.GetEnumerator();
}
}
3.利用ExpressionTree表达式树实现(探索中)
var source = typeof(Student);
var e = Expression.Parameter(source,"e");
//e.Gender
var sourceGender = Expression.MakeMemberAccess(e, source.GetProperty("Gender"));
//e.Age
var sourceAge = Expression.MakeMemberAccess(e, source.GetProperty("Age"));
//Gender = e.Gender
var assignGender = Expression.Bind(source.GetProperty("Gender"), sourceGender);
//Age => e.Age
var assignAge = Expression.Bind(source.GetProperty("Age"), sourceAge);
var target = Expression.New(typeof(Student));
// e=> new Student(){Gender = e.Gender,Age = e.Age}
var init = Expression.MemberInit(target, assignGender, assignAge);
var func = Expression.Lambda<Func<Student, object>>(init, e).Compile();
var allUnique = students.GroupBy(func).Where(o => o.Count() > 1).Select(c => c.ToList());
问题在于利用Expression表达式树生成的lambda必须指明类型,无法生成匿名类型,groupby需要匿名类型的分组条件,不然就得重写GetHashCode和Equal方法,我不想改动类就没有重写。或者可以尝试自己写一个比较器,传给groupby。