Skip to main content
 首页 » 编程设计

c#之汇总一个集合的所有属性并动态赋值给另一个对象

2024年01月31日25小虾米

我在 lst 中有一个对象集合类型 DataResponse我想做的是总结所有 int 的属性和 decimal这个集合的每个属性的结果分配给另一个对象 DataContainerResponse具有与正在汇总的属性名称(和类型)完全相同的属性名称(和类型)。

我可以通过手动输入每个属性并执行 .Sum(s=>s.<propertyname> 来手动执行此操作.但那是 90 年代。以下是我试图将其榨汁的无果而终的尝试。坦率地说,我以前从未将 var 分配给 lambda 表达式,我什至不知道这是否可能 .Sum(s=><var name>) ;

 public DataAggragationResponse doAggregation(List<DataResponse> lst) 
    { 
        if (lst.Count == 0) 
            return null; 
        DataContainerResponse rd = new DataContainerResponse(); 
 
        //If I do it manually typing each prop by hand. 
        rd.VIOL = lst.Sum(s => s.VIOL); 
 
 
        //Automation!!! 
        foreach (PropertyInfo propertyInfo in typeof(DataResponse).GetProperties()) 
        { 
 
                rd.GetType().GetProperties().SetValue(lst.Sum(s => propertyInfo.Name[0])); 
 
        } 
    } 

请您参考如下方法:

如果你想进行全反射,你可以试试下面的方法。我没有优化代码,而是尽可能快地完成了。对于凌乱的外观,我很抱歉,我假设聚合结果类和您要聚合的单元类中的属性名称相同。

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 年代了。 .