我在[{1}}类型lst
中有一个对象集合,我想要做的是总结DataResponse
和int
的所有属性收集并将每个属性的结果分配给另一个对象decimal
,该对象具有与要求总结的属性名称(和类型)相同的属性名称(和类型)。
我可以手动输入每个属性并执行DataContainerResponse
手动执行此操作。但那是90年代。以下是我毫无结果的尝试。坦率地说,我之前从未为lambda表达式分配过var,我甚至不知道它是否可能.Sum(s=>s.<propertyname>
;
.Sum(s=><var name>)
答案 0 :(得分:2)
希望这可以帮到你。我希望我保留SO链接到我刚才提出的问题。对于不提及他/她名字的原始海报感到抱歉。
using System.Reflection;
public static Dictionary<string, string> GetPropertiesValue(object o)
{
Dictionary<string, string> PropertiesDictionaryToReturn = new Dictionary<string, string>();
foreach (MemberInfo itemMemberInfo in o.GetType().GetMembers())
{
if (itemMemberInfo.MemberType == MemberTypes.Property)
{
//object PropValue = GetPropertyValue(OPSOP, item.Name);
//string itemProperty = itemMemberInfo.Name;
//string itemPropertyValue = o.GetType().GetProperty(itemMemberInfo.Name).GetValue(o, null).ToString();
//Console.WriteLine(itemProperty + " : " + itemPropertyValue);
PropertiesDictionaryToReturn.Add(itemMemberInfo.Name, o.GetType().GetProperty(itemMemberInfo.Name).GetValue(o, null).ToString());
}
}
return PropertiesDictionaryToReturn;
}
这不完全是你需要的,但我认为你可以适应它。
答案 1 :(得分:2)
如果您想要全面反思,可以尝试以下方法。我没有优化代码,尽可能快地完成。很抱歉凌乱的外观和Im假设聚合结果类中的属性名称和您要聚合的单元类相同。
class Program
{
static void Main(string[] args)
{
var list = new List<DataResponse>();
list.Add(new DataResponse() { Stuff = 1, Stuff2 = 2 });
list.Add(new DataResponse() { Stuff = 1, Stuff2 = 2 });
Stopwatch watch = new Stopwatch();
watch.Start();
var response = DoAggregationReflection(list);
watch.Stop();
Console.WriteLine(watch.Elapsed.TotalMilliseconds);
watch.Reset();
watch.Start();
var response2 = DoAggregation(list);
watch.Stop();
Console.WriteLine(watch.Elapsed.TotalMilliseconds);
}
public static DataAggragationResponse DoAggregationReflection(List<DataResponse> lst)
{
if (lst.Count == 0)
return null;
DataAggragationResponse aggrResponse = new DataAggragationResponse();
var responseType = typeof(DataResponse);
var aggrResponseType = typeof(DataAggragationResponse);
foreach (PropertyInfo propertyInfo in typeof(DataResponse).GetProperties())
{
aggrResponseType.GetProperty(propertyInfo.Name).SetValue(aggrResponse, lst.Sum(x => (int)responseType.GetProperty(propertyInfo.Name).GetValue(x)));
}
return aggrResponse;
}
public static DataAggragationResponse DoAggregation(List<DataResponse> lst)
{
if (lst.Count == 0)
return null;
DataAggragationResponse aggrResponse = new DataAggragationResponse();
aggrResponse.Stuff = lst.Sum(x => x.Stuff);
aggrResponse.Stuff2 = lst.Sum(x => x.Stuff2);
return aggrResponse;
}
}
public class DataResponse
{
public int Stuff { get; set; }
public int Stuff2 { get; set; }
}
public class DataAggragationResponse
{
public int Stuff { get; set; }
public int Stuff2 { get; set; }
}
但是,作为一个建议,如果你想采用这种方法,如果你可以缓存所有的反射调用,它会更好,因为它们很昂贵。 90年代的方法仍将在基准测试中获胜。像上面的示例一样,使用简单的StopWatch进行基准测试。
1.8193
0.4476
Press any key to continue . . .
第一个是DoAggregationReflection的执行时间,最后一个是DoAggregation的执行时间。您可以根据需要优化反射,但我认为它仍然无法与基本反射竞争。
有时90年代的情况会好一些。 ;)虽然你仍然使用LINQ进行实际求和,因此根据wikipedia,LINQ出生于2007年,不再是90年代了。
答案 2 :(得分:1)
我宁愿采取不同的方法。我会动态构建和编译(一次)这样的东西:
Func<DataContainerResponse, DataResponse, DataContainerResponse> aggregateFunc =
(result, item) =>
{
result.Prop1 += item.Prop1;
result.Prop2 += item.Prop2;
...
result.PropN += item.PropN;
return result;
}
(如果您想知道为什么签名如上所述,答案是 - 因为它可以直接用于以下Aggregate
重载。)
以下是如何做到的:
static readonly Func<DataContainerResponse, DataResponse, DataContainerResponse>
AggregateFunc = BuildAggregateFunc();
static Func<DataContainerResponse, DataResponse, DataContainerResponse> BuildAggregateFunc()
{
var result = Expression.Parameter(typeof(DataContainerResponse), "result");
var item = Expression.Parameter(typeof(DataResponse), "item");
var propertyTypes = new HashSet<Type> { typeof(decimal), typeof(int) };
var statements = item.Type.GetProperties()
.Where(p => propertyTypes.Contains(p.PropertyType))
.Select(p => Expression.AddAssign(
Expression.Property(result, p.Name),
Expression.Property(item, p)));
var body = Expression.Block(statements
.Concat(new Expression[] { result }));
var lambda = Expression.Lambda<Func<DataContainerResponse, DataResponse, DataContainerResponse>>(
body, result, item);
return lambda.Compile();
}
,用法很简单:
public DataContainerResponse DoAggregation(List<DataResponse> source)
{
return source.Aggregate(new DataContainerResponse(), AggregateFunc);
}