转置对象:反射还是复制?

时间:2018-07-30 13:01:17

标签: c#

我有一个由以下类定义的对象的列表:

internal class Aggregate
{
    public string fieldName { get; set; }
    public double Count { get; set; }
    public double Min { get; set; }
    public double Max { get; set; }
}

其中fieldName可以是ValueLowLimitHighLimit 我想要转换成定义为的对象列表:

public class KpiValue
{
    public double Value { get; set; }
    public double? LowLimit { get; set; }
    public double? HighLimit { get; set; }
    public AggregateType AggregateType { get; set; }
}
public enum AggregateType
{
    Count,
    Min,
    Max
}

我很天真地研究了它(用MCVE编辑):

var input = new List<Aggregate> {
            new Aggregate() {fieldName = "Value",Count = 5,Min = 2,Max = 3 },
            new Aggregate() {fieldName = "HighLimit",Count = 6,Min = 5,Max = 8 },
            new Aggregate() {fieldName = "LowLimit",Count = 2,Min = 9,Max = 15 } };

            List<KpiValue> values = new List<KpiValue>();
            values.Add(new KpiValue()
            {
                AggregateType = AggregateType.Count,
                Value = input.SingleOrDefault(l => l.fieldName == "Value").Count,
                HighLimit = input.SingleOrDefault(l => l.fieldName == "HighLimit").Count,
                LowLimit = input.SingleOrDefault(l => l.fieldName == "LowLimit").Count
            });
            values.Add(new KpiValue()
            {
                AggregateType = AggregateType.Min,
                Value = input.SingleOrDefault(l => l.fieldName == "Value").Min,
                HighLimit = input.SingleOrDefault(l => l.fieldName == "HighLimit").Min,
                LowLimit = input.SingleOrDefault(l => l.fieldName == "LowLimit").Min
            });
            values.Add(new KpiValue()
            {
                AggregateType = AggregateType.Count,
                Value = input.SingleOrDefault(l => l.fieldName == "Value").Max,
                HighLimit = input.SingleOrDefault(l => l.fieldName == "HighLimit").Max,
                LowLimit = input.SingleOrDefault(l => l.fieldName == "LowLimit").Max
            });

我一直在寻找一种改进的方法,并且似乎可以通过使用反射as in this question将代码放入循环中来实现。

但是,在阅读有关实现方法的内容时,我也了解到了这种反思is not very efficient, and that it is mostly used with external libraries

在这种情况下,Reflection是可行的方式,还是我应该保留重复的代码? (或者还有更好的第三种方法吗?)

编辑: 在这个例子中,性能并不是至关重要的,因为数据库调用非常长,由于反射引起的任何开销都不会引起注意。我只是在尝试the right thing™

1 个答案:

答案 0 :(得分:1)

您实际上不必重复代码,只需要将逻辑包装在一个方法中

public KpiValue BuildKpiValue(AggregationType aggregation, 
                              IEnumerable<Aggregate> list, 
                              Func<Aggregate, double> readValue)
{
    return new KpiValue()
    {
        AggregateType = aggregation,
        Value = readValue(list.Single(l => l.fieldName == "Value")),
        HighLimit = readValue(list.Single(l => l.fieldName == "HighLimit")),
        LowLimit = readValue(list.Single(l => l.fieldName == "LowLimit"))
    }
}

然后只需为每种聚合类型调用方法即可:

var input = new List<Aggregate> {
            new Aggregate() {fieldName = "Value",Count = 5,Min = 2,Max = 3 },
            new Aggregate() {fieldName = "HighLimit",Count = 6,Min = 5,Max = 8 },
            new Aggregate() {fieldName = "LowLimit",Count = 2,Min = 9,Max = 15 } };

List<KpiValue> values = new List<KpiValue>();
values.Add(BuildKpiValue(AggregationType.Count, input, agg => agg.Count));
values.Add(BuildKpiValue(AggregationType.Min, input, agg => agg.Min));
values.Add(BuildKpiValue(AggregationType.Max, input, agg => agg.Max));
// And so on for the other ones