产出不会产生预期的结果

时间:2015-01-06 04:57:04

标签: c# overloading constructor-chaining

这是我的代码:

class StockItem
{
    internal float CostPrice;
    internal string Description;
    internal static int LastStockNumber = 10000;
    internal int StockNumber;

    public StockItem(int StockNumber, string Description, float CostPrice): this(Description, CostPrice)
    {
        this.StockNumber = StockNumber;
    }

    public StockItem(string Description, float CostPrice)
    {
        LastStockNumber++;
        this.StockNumber = LastStockNumber;
        this.CostPrice = CostPrice;
        this.Description = Description;
    }

    public float GetCostPrice()
    {
        return CostPrice;
    }

    public virtual string Print() //is virtual (Polymorphic)
    {
        string Output = "";
        Output += "\r\n\r\n";
        Output += "Stock Item: ";
        Output += "\r\n";
        Output += "Stock No: " + StockNumber;
        Output += "\r\n";
        Output += "Desc: " + Description;
        Output += "\r\n";
        Output += "Cost: " + CostPrice;
        Output += "\r\n";
        return Output;
      }
    }
}

class HeavyStockItem : StockItem
{
    internal float Weight;

    public HeavyStockItem(int StockNumber, string Description, float CostPrice, float Weight)
        : base(StockNumber, Description, CostPrice)
    {
        this.Weight = Weight;
    }

    public HeavyStockItem(string Description, float CostPrice, float Weight)
        : base(Description, CostPrice)
    {
        LastStockNumber++;
        this.StockNumber = LastStockNumber;
        this.Weight = Weight;
    }

    public float GetWeight()
    {
        return Weight;
    }

    public override String Print() //overriding StockItem.Print and adds wieght to the bottom 
    {
        string Output = "";
        Output += base.Print();
        Output += "Weight: " + Weight + "\r\n";
        return Output;
      }
    }
}

class CarEngine : HeavyStockItem
{
    internal string EngineNumber;

    public CarEngine(int StockNumber, string Description, float CostPrice, float Weight, string EngineNumber)
        : base(StockNumber, Description, CostPrice, Weight)
    {
        this.EngineNumber = EngineNumber;
    }

    public CarEngine(string Description, float CostPrice, float Weight, string EngineNumber)
        : base(Description, CostPrice, Weight)
    {
        LastStockNumber++;
        this.StockNumber = LastStockNumber;
    }

    public override String Print() //overriding StockItem.Print and adds engine number to the bottom 
    {
        string Output = "";
        Output += base.Print();
        Output += "EngineNumber: " + EngineNumber + "\r\n";
        return Output;
    }
  }
}

public partial class Form1 : Form
{
    StockItem StockItem1;
    CarEngine StockItem2;
    CarEngine StockItem3;
    StockItem StockItem4;
    HeavyStockItem StockItem5;

    private void ShowItem (StockItem PrintStockItem)
    {
        txtOutput.Text += PrintStockItem.Print();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        StockItem1 = new StockItem(StockItem.LastStockNumber, "Scrediwer set", 42);
        StockItem2 = new CarEngine(8025, "MazdaB6T", 1252, 800, "Z4537298D");
        StockItem3 = new CarEngine(StockItem.LastStockNumber, "Holden 308", 958, 1104, "P74623854S");
        StockItem4 = new StockItem(8002, "Trolley Jack", 127);
        StockItem5 = new HeavyStockItem(HeavyStockItem.LastStockNumber, "JD Caterpillar Track", 3820, 2830);
    }

    private void btnList_Click(object sender, EventArgs e) //polymorfic call
    {
        ShowItem(StockItem1);
        ShowItem(StockItem2);
        ShowItem(StockItem3);
        ShowItem(StockItem4);
        ShowItem(StockItem5);
    }
  }
}

这是我的输出:

Stock Item: 
Stock No: 10000
Desc: Scrediwer set
Cost: 42

Stock Item: 
Stock No: 8025
Desc: MazdaB6T
Cost: 1252
Weight: 800
EngineNumber: Z4537298D

Stock Item: 
Stock No: 10002
Desc: Holden 308
Cost: 958
Weight: 1104
EngineNumber: P74623854S

Stock Item: 
Stock No: 8002
Desc: Trolley Jack
Cost: 127

Stock Item: 
Stock No: 10004
Desc: JD Caterpillar Track
Cost: 3820
Weight: 2830

我的问题是:

而不是获得1,3和1号商品的库存号5为10000,10001& 10002我按上述方式得到。不明白为什么?

2 个答案:

答案 0 :(得分:1)

接受特定StockNumber的StockItem构造函数正在调用增加LastStockNumber其他构造函数。因此,每次创建StockItem的实例(或从StockItem派生的内容)时,即使在构造函数中指定了库存号,LastStockNumber也会递增。

实际上,您在许多构造函数中递增LastStockNumber,这会导致在创建某些类型的对象时它至少增加两次。


修改

至于如何解决这个问题,我首先要改变使用LastStockNumber的StockItem构造函数,这样它就不会调用其他构造函数,而只是设置价格和描述本身:

public StockItem(int StockNumber, string Description, float CostPrice)
{
    this.StockNumber = StockNumber;
    this.CostPrice = CostPrice;
    this.Description = Description;
}

然后我删除你在派生类的构造函数中增加LastStockNumber的其他地方。

您还应将LastStockNumber设为私有。进行这些更改后,如果继续按照您的方式创建对象,LastStockNumber将永远不会增加,因为您始终在创建对象时指定库存编号。

答案 1 :(得分:0)

您正在呼叫的CarEngine的构造函数,

    StockItem2 = new CarEngine(8025, "MazdaB6T", 1252, 800, "Z4537298D");

public CarEngine(int StockNumber, string Description, float CostPrice, 
                 float Weight, string EngineNumber)
    : base(StockNumber, Description, CostPrice, Weight)

反过来调用下面的基类构造函数:

public StockItem(int StockNumber, string Description, float CostPrice): this(Description, CostPrice)
{
   this.StockNumber = StockNumber;

直接设置StockNumber。

同样,Trolley直接使用相同的StockItem构造函数构建:

  StockItem4 = new StockItem(8002, "Trolley Jack", 127);

看起来,你想调用另一个StockItem构造函数,即增加静态计数器的构造函数:

 public StockItem(string Description, float CostPrice)

顺便说一句,请注意,如果您使用浮点变量来存储货币,则可能会遇到舍入问题,例如: float CostPrice。我建议改为使用decimal

修改

FWIW我会按如下方式重新设计您的基础StockItem类,以封装属性,并控制增量库存号的分配。另请注意,静态变量容易出现线程安全问题。

internal class StockItem
{
    // Private to prevent externals + subclasses from mutating this
    private static int _lastStockNumber = 10000;

    // Convert to properties and private setters force subclasses to use the Ctor
    public decimal CostPrice { get; private set; }
    public string Description { get; private set; }
    public int StockNumber { get; private set; }

    // Static is now read only
    public static int LastStockNumber
    {
        get { return _lastStockNumber; }
    }

    // Constructor not allowing for setting of Stock Number
    public StockItem(string description, decimal costPrice)
    {
        Interlocked.Increment(ref _lastStockNumber);
        this.CostPrice = costPrice;
        this.Description = description;
    }

    // Constructor allowing for direct setting of stockNumber
    public StockItem(int stockNumber, string description, decimal costPrice)
    {
        this.StockNumber = stockNumber;
        this.CostPrice = costPrice;
        this.Description = description;
    }
}

上面将强制子类使用上面的一个构造函数来设置基类属性,并且,如果适用的话,以更加受控和线程安全的方式从静态自动分配StockNumber。

最后,基类也可以使用自动属性,而不是显式的getter方法,即替换

public float GetWeight()
{
    return Weight;
}

public Weight {get; private set;}