在我的应用程序中,我创建了大量只包含一些数据的“小”类实例。
我知道类创建(即构造函数调用)代价很高。我的问题是:如果我让这个小类继承自另一个类,会不会更昂贵?有些字段只会移动到超类,所以基本上我只能使用
注意:此问题专门针对.NET中的性能。
考虑这2个案例:
1。案例只包含一个类。这是原来的课程:
public class ShapeWithOffset{
public double XOffset { get; private set; }
public double YOffset { get; private set; }
public IShape Shape{ get; private set; }
public ShapeWithOffset(double xOffset, double yOffset, IShape shape){
//check if arguments are correct/throw ArgumentException if not
XOffset = xOffset;
YOffset = yOffset;
Shape = shape;
}
//equality members
}
2。 case 由2个类组成,其中second从第一个继承。第二课ShapeWithHorizontalAndVerticalOffset
在1. case中提供与ShapeWithOffset
相同的功能。
public class ShapeWithHorizontalOffset{
public double XOffset { get; private set; }
public IShape Shape { get; private set; }
public ShapeWithHorizontalOffset(double xOffset, IShape shape){
//check if arguments are correct/throw ArgumentException if not
XOffset = xOffset;
Shape = shape;
}
//equality members
}
public class ShapeWithHorizontalAndVerticalOffset : ShapeWithHorizontalOffset{
public double YOffset { get; private set; }
public ShapeWithHorizontalAndVerticalOffset(double xOffset, double yOffset,
IShape shape) : base(xOffset, shape){
//check if yOffset is correct/throw ArgumentOutOfRangeException if not
Yffset = yOffset;
}
//equality members
}
我的问题是:命令var foo = new ShapeWithOffset(20, 10, shape);
是否比
更快
var boo = new ShapeWithHorizontalAndVerticalOffset(20, 10, shape);
?
如果我使用的是组合而不是继承,那就是......但是继承呢?
答案 0 :(得分:8)
你问题中的关键词是“......我想......”。如果你知道自己遇到了性能问题,那就找出瓶颈并对其进行优化。如果您预计会出现性能问题,请不要!以建议的方式使用继承会导致任何性能瓶颈的可能性极小。但是,如果你真的想提前知道,请提前测试。
答案 1 :(得分:5)
这几乎是一样的。 JITter将内联调用base .ctor,并且仅执行一次分配。它只需要花费几个字节作为开销。
如果您不确定,请尝试一个小基准。
答案 2 :(得分:3)
我使用分析器进行微优化代码的经验是方法调用开销可以忽略不计。我在性能改进方面的主要胜利几乎总是:缓存经常使用的计算,优化深内循环(通常使用直接数组索引而不是枚举)并避免不必要的装箱。当然,所有这些都相形见绌,通过改进算法来减少迭代次数(通常通过引入启发式而不是早期排除分支或将问题转换为单独的'聚合'和'细节'阶段。)
答案 3 :(得分:1)
首先,正如我在评论中所说,调用基础构造函数(和虚拟方法)并不会影响性能,足以证明它失去了它为程序带来的可维护性和表现力。如果在这种情况下性能确实存在问题,那么结构化语言将不存在。
现在,从设计的角度来看,问题被简化为继承在您的情况下是否真正有利可图。这提示了一个问题:为什么ShapeWithOffset
无法从Shape
派生出来?如果有可能的话,我可能会切断复杂性并做一些事情:
public class ShapeWithOffset : Shape
{
public ShapeWithOffset(double xOffset)
: this(xOffset, 0.0) {}
public ShapeWithOffset(double xOffset, double yOffset)
{
// TODO - Check if arguments are correct/throw ArgumentException if not.
XOffset = xOffset;
YOffset = yOffset;
}
}
在C#4中,你甚至可以写:
public ShapeWithOffset(double xOffset, double yOffset = 0.0)
{
// TODO - Check if arguments are correct/throw ArgumentException if not.
XOffset = xOffset;
YOffset = yOffset;
}
答案 4 :(得分:0)
一般性地谈论继承(特别是你的情况),因为kuchana在他的书(设计模式)中试图避免继承,如果没有必要,因为它的复杂性。 我认为运行时绑定可能会导致小的性能问题,但继承的主要开销是它的设计复杂性,这比微小的性能问题重要得多。
修改
我现在意识到这个问题是关于构建:D。 以下段落在java中也是如此,也许在.Net中也是如此。 我认为,如果你明确定义你的子类中的构造函数,它将没有任何区别,因为编译器将首先在子类中查找构造函数,如果没有找到,它将在继承层次结构中,直到他!找到合适的构造函数。