有没有一种优雅的方式来做到这一点?
假设我正在使用具有专用数字属性(整数和双精度数)的对象,如下所示:
Foo
-bar1 int
-bar2 int
-bar3 int
-foobar1 double
-foobar2 double
我有一个 List 集合......有没有办法让它简单地将 List 中的所有数字属性相加并返回一个包含所有总数的单个对象 Foo?
一如既往的感谢
如果我正确理解了您的问题,并且您想要获得一个Foo
实例,其中每个成员是列表中存在的所有相应Foo
实例成员的总和,那么一种可能的(有点冗长,但直接不涉及魔法)方式就是使用 linq 聚合:
// Simplified Foo to prevent a lot of typing.
public class Foo
{
public int bar1 { get; set; }
public int bar2 { get; set; }
public double foobar1 { get; set; }
}
var myFooList = new List<Foo>
{
new Foo() { bar1 = 1, bar2 = 2, foobar1 = 20.0 },
new Foo() { bar1 = 5, bar2 = 8, foobar1 = 42.0 },
new Foo() { bar1 = 9, bar2 = 3, foobar1 = -10.0 },
};
var myFooSum = myFooList.Aggregate(new Foo(), (curSum, foo) =>
{
curSum.bar1 += foo.bar1;
curSum.bar2 += foo.bar2;
curSum.foobar1 += foo.foobar1;
return curSum;
});
Console.WriteLine("FooSum: bar1 = {0}, bar2 = {1}, bar3 = {2}", myFooSum.bar1, myFooSum.bar2, myFooSum.foobar1);
印刷:
FooSum: bar1 = 15, bar2 = 13, bar3 = 52
如果我误解了,并且您想要将任意对象列表(其中一些可能包含多个数字字段)汇总为单个总和值,那么@Simon Whitehead 建议的方法可能会起作用:
public class Bar
{
public int baz { get; set; }
public double booz { get; set; }
public string nonNumeric { get; set; }
}
static double SumNumericalProperties(object obj)
{
if (obj == null)
return 0;
if (obj is int)
return (int)obj;
if (obj is double)
return (double)obj;
// etc for other numeric types.
var sum = 0.0;
foreach (var prop in obj.GetType().GetProperties())
{
if (typeof(int).IsAssignableFrom(prop.PropertyType))
sum += (int)prop.GetValue(obj);
else if (typeof(double).IsAssignableFrom(prop.PropertyType))
sum += (double)prop.GetValue(obj);
// etc for other numeric types.
}
return sum;
}
var myObjectList = new List<object>
{
new Foo() { bar1 = 1, bar2 = 2, foobar1 = 20.0 },
new Bar() { baz = 10, booz = 100.0 },
24,
33.3333,
new Foo() { bar1 = 5, bar2 = 8, foobar1 = 42.0 },
new Foo() { bar1 = 9, bar2 = 3, foobar1 = -10.0 },
};
var myFooSum = myObjectList.Sum(SumNumericalProperties);
Console.WriteLine("Sum = {0}", myFooSum);
哪个打印:
Sum = 247.3333
也可以使用这个单线来完成 :-)
Item sum = (from p in typeof(Item).GetFields()
where Type.GetTypeCode(p.FieldType) == TypeCode.Int32 || Type.GetTypeCode(p.FieldType) == TypeCode.Double
group p by p into g
select new { Prop=g.Key, Sum=items.Sum(s => (decimal)Convert.ChangeType(g.Key.GetValue(s), TypeCode.Decimal)) })
.Aggregate(new Item(), (state, next) => {
next.Prop.SetValue(state, Convert.ChangeType(next.Sum, next.Prop.FieldType));
return state;
});
完整样本:
using System;
using System.Linq;
using System.Collections.Generic;
class Program
{
class Item
{
public int bar1 = 0;
public int bar2 = 0;
public double foobar1 = 0;
public double foobar2 = 0;
}
public static void Main ()
{
var items = new List<Item>();
items.Add(new Item() { bar1 = 1, bar2 = 2, foobar1 = 1.1, foobar2 = 1.2 });
items.Add(new Item() { bar1 = 1, bar2 = 2, foobar1 = 1.1, foobar2 = 1.2 });
items.Add(new Item() { bar1 = 1, bar2 = 2, foobar1 = 1.1, foobar2 = 1.2 });
var sum = (from p in typeof(Item).GetFields()
where Type.GetTypeCode(p.FieldType) == TypeCode.Int32 || Type.GetTypeCode(p.FieldType) == TypeCode.Double
group p by p into g
select new { Prop=g.Key, Sum=items.Sum(s => (decimal)Convert.ChangeType(g.Key.GetValue(s), TypeCode.Decimal)) })
.Aggregate(new Item(), (state, next) => {
next.Prop.SetValue(state, Convert.ChangeType(next.Sum, next.Prop.FieldType));
return state;
});
Console.WriteLine("bar1: " + sum.bar1);
Console.WriteLine("bar2: " + sum.bar2);
Console.WriteLine("foobar1: " + sum.foobar1);
Console.WriteLine("foobar2: " + sum.foobar2);
}
}
粗略的尝试:
private static double sumNumericalProperties<T>(T obj)
{
var result = 0d;
foreach (var prop in typeof (T).GetProperties())
{
if (typeof(int).IsAssignableFrom(prop.PropertyType))
{
result += (int)prop.GetValue(obj);
}
else if (typeof(double).IsAssignableFrom(prop.PropertyType))
{
result += (double) prop.GetValue(obj);
}
}
return result;
}
示例输入:
class Foo
{
public int Bar1 { get; set; }
public int Bar2 { get; set; }
public double Foobar1 { get; set; }
public double Foobar2 { get; set; }
public string BufferProperty { get; set; }
}
var obj = new Foo() {Bar1 = 2, Bar2 = 4, Foobar1 = 5, Foobar2 = 6};
var obj2 = new Foo() { Bar1 = 2, Bar2 = 4, Foobar1 = 5, Foobar2 = 7 };
var list = new List<Foo>();
list.Add(obj); // 17
list.Add(obj2); // 18
Console.WriteLine(list.Sum(x => sumNumericalProperties(x))); // 35