我有一个类,如下所示示例类。在我的 DoSomeLogic 方法中,我需要对示例类的集合求和,并希望返回示例类的新实例,其中每个数字属性都包含该集合中该属性的总和。
下面是我通常如何执行此操作的示例,但我的问题是我不断更新示例类,添加新属性等。执行此操作时,我需要记住也更新示例类的 sum 方法,或者我的代码已损坏,这似乎是我想避免的障碍/漏洞。
任何人都可以向我展示一种更好的方法来执行此操作,这样如果我向示例类添加新的数字属性,我就不需要更新 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;}
}
Run Code Online (Sandbox Code Playgroud)
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;
}
}
Run Code Online (Sandbox Code Playgroud)
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;
}
}
Run Code Online (Sandbox Code Playgroud)
您可以使用反射来解决这个问题,但我认为这太过分了(并且性能不会很好)。
您可以考虑将“添加”功能放入类本身中:
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 void Add(Example other)
{
A += other.A;
B += other.B;
C += other.C;
}
public int A { get; set; }
public int B { get; set; }
public float C { get; set; }
public string IgnoreThis { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
那么你的扩展方法将变成:
public static Example Sum(this IEnumerable<Example> source)
{
var result = new Example();
foreach (var example in source)
{
result.Add(example);
}
return result;
}
Run Code Online (Sandbox Code Playgroud)
当您向类添加新成员时,Example您需要Add()相应地更新方法,但不需要修改扩展方法。
附录:由于有人想知道INumber在使用反射的实现中使用,我想我应该尝试一下。
首先,这是一个您想要对其属性求和的示例类:
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 override string ToString()
{
return $"A={A}, B={B}, C={C}";
}
public int A { get; set; }
public int B { get; set; }
public float C { get; set; }
public string IgnoreThis { get; set; } = "";
}
Run Code Online (Sandbox Code Playgroud)
下面是一个示例程序,演示了我们如何添加集合中所有项目的属性。请注意预期输出:
public static class Program
{
public static void Main()
{
var items = new[]
{
new Example(1, 4, 7),
new Example(2, 5, 8),
new Example(3, 6, 9)
};
var totals = Extension.SumNumericProperties(items);
Console.WriteLine(totals); // A=6, B=15, C=24
}
}
Run Code Online (Sandbox Code Playgroud)
这是我实现该类的方法Extension:
如果您需要添加其他数字类型(例如decimal),您只需添加numericProperties具有所需类型的新项目并添加对sumValueTo()和 的调用assignResults()。
public static class Extension
{
public static T SumNumericProperties<T>(IEnumerable<T> items) where T: new()
{
var intAdders = numericProperties<int, T>();
var floatAdders = numericProperties<float, T>();
var shortAdders = numericProperties<short, T>();
var doubleAdders = numericProperties<double, T>();
foreach (var item in items)
{
sumValueTo(intAdders, item);
sumValueTo(floatAdders, item);
sumValueTo(shortAdders, item);
sumValueTo(doubleAdders, item);
}
T result = new();
assignResults(intAdders, result);
assignResults(floatAdders, result);
assignResults(shortAdders, result);
assignResults(doubleAdders, result);
return result;
}
static void sumValueTo<TNumber, T>(List<NumericPropertyAdder<TNumber>> numericProperties, T item) where TNumber : INumber<TNumber>
{
foreach (var numericProperty in numericProperties)
{
numericProperty.Add(item!);
}
}
static void assignResults<TNumber, T>(List<NumericPropertyAdder<TNumber>> numericProperties, T item) where TNumber : INumber<TNumber>
{
foreach (var numericProperty in numericProperties)
{
numericProperty.AssignResult(item!);
}
}
static List<NumericPropertyAdder<TNumber>> numericProperties<TNumber, TOwner>() where TNumber : INumber<TNumber>
{
return (
from prop in typeof(TOwner).GetProperties()
where prop.PropertyType.IsAssignableTo(typeof(INumber<TNumber>))
select new NumericPropertyAdder<TNumber>(prop)
).ToList();
}
}
public sealed class NumericPropertyAdder<T> where T: INumber<T>
{
public NumericPropertyAdder(PropertyInfo property)
{
_property = property;
}
public void Add(object propertyHolder)
{
var value = (T) _property.GetValue(propertyHolder)!;
_sum += value;
}
public T Sum()
{
return _sum;
}
public void AssignResult(object propertyHolder)
{
_property.SetValue(propertyHolder, _sum);
}
T _sum = T.AdditiveIdentity;
readonly PropertyInfo _property;
}
Run Code Online (Sandbox Code Playgroud)
我的结论是,处理这样的泛型类型所增加的复杂性实际上可能不值得......;)
| 归档时间: |
|
| 查看次数: |
134 次 |
| 最近记录: |