C#访问者应该使用私有变量还是动态计算?

时间:2010-08-24 17:57:35

标签: c# performance accessor

哪种编程方法更好?为什么?

我有一个这样的课程:

class data {

    public double time { get; internal set; }
    public double count { get; internal set; }
    public average_count { ... }

}

其中average_count应为read_only并计算计数/时间。

将访问者编写为:

是否更好
public average_count { get {

    return (time == 0) ? 0 : (count / time);

}}

或者我应该做点什么:

private _avg_count;

public average_count {
    get 
    {
        return _avg_count;
    }

    internal set
    {
        return _avg_count;
    }
}

在时间和计数集访问器中更新_avg_count的位置?

似乎第一个更易于阅读,但如果经常访问average_count则可能会更慢。编译器优化是否会使差异无关紧要?

8 个答案:

答案 0 :(得分:13)

动态执行此操作会产生更易读的代码。预先计算可以提高性能,但是只有在(a)必要时和(b)您进行了分析并且它会产生影响时才应该这样做。

最重要的是,可读性和可维护性应该在绝对必要时牺牲性能

答案 1 :(得分:5)

这是一个看似简单的问题,但几乎不可能回答。原因在于“正确”取决于许多因素。

1。性能

在他的回答Skilldrick中,建议您更喜欢可读性优于一般规则的内容:

  

[R]可扩展性和可维护性应该   因性能而牺牲   什么时候绝对必要。

我会反驳说,在典型的商业应用程序中为真,其中性能和功能是两个明显可区分的功能。在某些高性能软件场景中,这并不是一件容易的事情,因为性能和功能可能会变得密不可分 - 也就是说,如果程序完成任务的程度取决于它的执行情况(这种情况就是如此)我目前的工作地点,一家从事算法交易的公司。)

所以这是你的判断。最好的建议是在你有一个问题时进行分析;如果在你的情况下牺牲性能的可读性是合适的,那么你应该这样做。

2。内存使用

0xA3提出了一种相当优雅的方法,可以对各种类型进行折衷:只根据需要计算值,然后对其进行缓存。

方法的缺点当然是需要更多内存来维护。 int?需要与int加上bool基本相同的内存量(由于对齐问题,实际上可能意味着64位而不是40位)。如果你有这个data类的实例的加载和加载,并且内存是你所瞄准的平台上的稀缺资源,那么每个实例的另外32位膨胀你的类型可能不是最聪明的举动。

3。可维护性

那就是说,我一般都同意其他人所说的,在其他条件相同的情况下,你最好在可读性方面犯错误,以便在将来重新审视时能够理解你的代码。但是,解决这个问题的各种方法都没有特别复杂。

最重要的是,只有你知道自己的具体情况,因此你才能最好地决定在这里做什么。

答案 2 :(得分:4)

具体取决于您拨打average_count的频率以及counttime的修改频率。对于这种优化,我建议你使用profiler。

答案 3 :(得分:4)

如果性能很关键并且您需要经常访问该属性,那么您还有另一个选项:在需要时计算结果,然后缓存结果。模式看起来像这样:

class Foo
{
    int? _cachedResult = null;

    int _someProperty;
    public int SomeProperty
    {
        get { return _someProperty; }
        set { _someProperty = value; _cachedResult = null; }
    }

    int _someOtherProperty;
    public int SomeOtherProperty
    {
        get { return _someOtherProperty; }
        set { _someOtherProperty = value; _cachedResult = null; }
    }

    public int SomeDerivedProperty
    {
        get
        {
            if (_cachedResult == null)
                _cachedResult = someExpensiveCalculation();

            return (int)_cachedResult;
        }
    }
}

答案 4 :(得分:1)

在这个简单的例子中,我肯定会首先实现计算版本;然后根据需要进行优化。如果存储该值,则还需要额外的代码来重新计算值,如果它所依赖的任何值发生更改,则会导致出现错误。

不要过早优化。

答案 5 :(得分:1)

我会选择你的第一个选择。这些是内存中的对象,因此对你正在做的事情的计算将非常快。此外,如果您为此创建了一个专用属性(例如,average_count),那么您将不得不添加 more 代码,以便在setter中重新计算时间和计数。< / p>

作为附注(因为您询问最佳实践),您应该在C#中使用Pascal大小写,这是初始大写且没有下划线。

答案 6 :(得分:0)

  
    

编译器优化是否会使差异无关紧要?

  

取决于您认为“重要”的内容。阅读变量很快。划分两个数字相当快。实际上,根据RAM缓存中的内容,读取变量可能需要比分割时间更长的时间。

使用第一种方法。如果它看起来很慢,那么考虑第二个。

答案 7 :(得分:0)

如果您关心线程安全,那么第二个选项可能比第一个选项更容易。

private double _avg_count;
static readonly object avgLock = new object();

public double time { get; internal set; }
public double count { get; internal set; }


public double average_count {
    get 
    {
        return _avg_count;
    }


}

private void setAverageCount()
{
    _avg_count = time == 0 ? 0 : (count / time);
}


 public void Increment()
 {
     lock (avgLock)
     {
         count += 1;
         setAverageCount();
     }


 }


 public void EndTime(double time)
 {
     lock (avgLock)
     {
         time = time;
         setAverageCount();

     }
 }