You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现类中数值属性的通用求和,无需随属性更新修改代码?

通用实现类集合数值属性求和,无需手动维护求和逻辑

我有一个Example类,需要对其集合执行求和操作,返回一个新的Example实例,其中每个数值属性的值为集合中对应属性的总和。目前手动编写的Sum扩展方法在新增类属性时必须同步修改,否则会出错,希望找到一种通用实现,新增数值属性时无需修改求和方法。

原代码如下:

public class Example 
{
    public Example()
    {
    }

    public Example(int a, int b, float c)
    {
        A = a;
        B = b;
        C = c;
        IgnoreThis = "Non numerical properties should be ignored by the sum method";
    }

    public int A { get; set; }
    public int B { get; set; }
    public float C { get; set; }
    public string IgnoreThis {get; set;}
}
using System.Collections.Generic;
using System.Linq;

public static class Extension
{
    public static Example Sum(this IEnumerable<Example> source)
    {
        Example result = new Example();
        result.A = source.Sum(x => x.A);
        result.B = source.Sum(x => x.B);
        result.C = source.Sum(x => x.C);
        return result;
    }
}
using System.Collections.Generic;

public class Usage
{
    private List<Example> Examples = new List<Example>();

    public void DoSomeLogic()
    {
        Examples.Add(new Example(1, 2, 3.75f));
        Examples.Add(new Example(2, 3, 6.25f));
        Example SumOfEachIndividualProperty = Examples.Sum();
        //Expected result from logging SumOfEachIndividualProperty.A is 3;
        //Expected result from logging SumOfEachIndividualProperty.B is 5;
        //Expected result from logging SumOfEachIndividualProperty.C is 10;
    }
}

解决方案:基于反射的通用求和实现

可以利用反射自动识别类中的数值属性并完成求和逻辑,新增数值属性时无需修改求和方法。

修改后的通用扩展方法

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

public static class Extension
{
    public static Example Sum(this IEnumerable<Example> source)
    {
        if (source == null) throw new ArgumentNullException(nameof(source));
        
        var result = new Example();
        var type = typeof(Example);
        
        // 筛选出可读写的公共数值属性(排除非数值类型)
        var numericProperties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance)
            .Where(p => IsNumericType(p.PropertyType) && p.CanRead && p.CanWrite);
        
        foreach (var prop in numericProperties)
        {
            // 动态计算属性总和,兼容不同数值类型
            var sum = source.Aggregate(Activator.CreateInstance(prop.PropertyType) as dynamic, 
                (accumulator, item) => accumulator + prop.GetValue(item) as dynamic);
            
            // 将总和赋值给结果实例的对应属性
            prop.SetValue(result, sum);
        }
        
        return result;
    }
    
    // 判断是否为有效数值类型(排除bool等非计算用类型)
    private static bool IsNumericType(Type type)
    {
        // 处理可空数值类型
        type = Nullable.GetUnderlyingType(type) ?? type;
        
        return type == typeof(int) || type == typeof(float) || type == typeof(double)
            || type == typeof(long) || type == typeof(decimal) || type == typeof(short)
            || type == typeof(byte) || type == typeof(uint) || type == typeof(ulong)
            || type == typeof(ushort) || type == typeof(sbyte);
    }
}

核心说明

  • 自动识别属性:通过反射获取Example类的所有公共实例属性,自动筛选出符合条件的数值属性,无需手动指定。
  • 动态类型兼容:使用dynamic处理不同数值类型的加法操作,避免针对每种类型编写重复求和逻辑。
  • 无侵入扩展:新增数值属性(如public int D { get; set; })时,无需修改Sum方法,反射会自动识别新属性并参与求和。

性能优化(可选)

如果需要高频调用求和方法,可以缓存数值属性信息,避免每次反射的开销:

public static class Extension
{
    // 缓存数值属性,仅初始化一次
    private static readonly PropertyInfo[] _cachedNumericProperties = typeof(Example)
        .GetProperties(BindingFlags.Public | BindingFlags.Instance)
        .Where(p => IsNumericType(p.PropertyType) && p.CanRead && p.CanWrite)
        .ToArray();
    
    public static Example Sum(this IEnumerable<Example> source)
    {
        if (source == null) throw new ArgumentNullException(nameof(source));
        
        var result = new Example();
        
        foreach (var prop in _cachedNumericProperties)
        {
            var sum = source.Aggregate(Activator.CreateInstance(prop.PropertyType) as dynamic, 
                (accumulator, item) => accumulator + prop.GetValue(item) as dynamic);
            
            prop.SetValue(result, sum);
        }
        
        return result;
    }
    
    // IsNumericType方法不变
    private static bool IsNumericType(Type type)
    {
        type = Nullable.GetUnderlyingType(type) ?? type;
        return type == typeof(int) || type == typeof(float) || type == typeof(double)
            || type == typeof(long) || type == typeof(decimal) || type == typeof(short)
            || type == typeof(byte) || type == typeof(uint) || type == typeof(ulong)
            || type == typeof(ushort) || type == typeof(sbyte);
    }
}

内容的提问来源于stack exchange,提问作者MattFace

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 22:12:18