检查“计算”类

时间:2016-05-05 13:38:27

标签: c# .net string memory decimal

我有以下“计算”课程。

public class Foo
{

    private int? _sum = 0;

    public int Sum
    {
        get
        {
            if (_sum == null)
                _sum = 1 + 1; //simple code to show "some" calculation happens...

            return _sum.GetValueOrDefault();
        }
    }

}

在这个示例中,只有1个Field / Member,但在我的真实课程中,大约有50个成员,所有成员看起来都相似,只是进行了不同的值计算。

在课堂上我也有Recalc方法。

这个Recalc方法做了4件事

  1. 保存旧值
  2. 将所有字段设置为空
  3. 调用每个成员的getter
  4. 检查旧值是否与newvalues不同并做相关的事情
  5. 我不确定这是存储旧值并使用新值检查更改的最佳方法。

    我目前的实施是:

    public string GetValuesKey()
    {
        //again this method only handles the 1 Member and not all 50 in real app its string.Format("{0}|{1}|{2}|...{49}|{50}|", ....);
        return string.Format("{0}|", this.Sum);
    }
    
    public void Recalc()
    {
        var oldValues = GetValuesKey();
    
        //set all fields to null
        //call the getters
    
        var newValues = GetValuesKey();
        if (oldValues != newValues)
        {
            //something changed...
        }
    }
    

    但是这个代码有一个内存/性能问题,因为我正在用结构(十进制)写入引用类型(字符串)。

    我有点想阻止为所有成员做50个额外的字段(如_oldSum)。 我只需要在Recalc程序中检查是否有任何成员发生了变化。

    以防万一,我无法执行以下代码。

    public void Recalc()
    {
        var changes = false;
    
        var oldValue = this.Sum;
        _sum = null;
        var newValue = this.Sum;
        if (oldValue != newValue)
            changes = true;
    
        //check next member
        oldValue = this.Sum2;
        _sum2 = null;
        newValue = this.Sum2;
        if (oldValue != newValue)
            changes = true;
    
        //check next member and so on...
    }
    

    因为我需要首先将所有字段设置为null,并且只有在所有字段都设置为null之后我才能执行getter,因为如果Sum Member会聚合其他两个成员,那么成员依赖于彼此。他们还没有被设置为null,他们仍然会有旧值。

    因此,我需要一种方法来存储代表所有值的内容,然后再将字段设置为null,并在调用成员的getter之后检查更改。

    欢迎任何帮助。

    修改

    这是代码,我写的是测试性能/内存: http://pastebin.com/3WiNJHyS

2 个答案:

答案 0 :(得分:1)

如果您不想自己编写所有50个_oldValue字段,唯一的选择是使用Reflection,这意味着一些装箱/拆箱,因此性能不是最好的。

无论如何,在以下实现中,我假设在Foo类中,计算中涉及的成员都是唯一属于decimal?类型属性的成员。 否则,我们需要一个更复杂的解决方案,在所涉及的每个字段/属性上都有BindingFlags和/或Attribute,依此类推。

public void Recalc()
{
    var propertyInfos = GetType()
        .GetProperties()
        .Where(pInfo => pInfo.PropertyType.IsValueType);

    var fieldInfos = GetType()
        .GetFields()
        .Where(fInfo => fInfo.FieldType.IsValueType);

    //create a dictionary with all the old values
    //obtained from the backing fields.
    var oldValueDictionary = fieldInfos.ToDictionary(
        fInfo => fInfo.Name,
        fInfo => (decimal?)fInfo.GetValue(this));

    //set all properties to null
    foreach (var pInfo in propertyInfos)
        pInfo.SetValue(this, null);

    //call all the getters to calculate the new values
    foreach (var pInfo in propertyInfos)
        pInfo.GetValue(this);

    //compare new field values with the old ones stored in the dictionary;
    //if only one different is found, the if is entered.
    if (fieldInfos.Any(fInfo =>
        (decimal?)fInfo.GetValue(this) != oldValueDictionary[fInfo.Name]))
    {
        //do stuffs
    }
}

最后请注意,您的班级配置非常奇怪。您确定在吸气剂中设置所有计算是最佳选择吗?也许你应该重新考虑一下你的设计。一个任务是检索属性值(一个getter),另一个任务是计算某些东西(从支持字段中存储的某个值开始)...

答案 1 :(得分:1)

不是将字符串中的所有值组合在一起并且在字符串构造上有一些特性 - 将所有值放在数组(decimal)中,然后将所有字段设置为null,进行计算并比较旧数组和新的价值观。

相关问题